feat: Konfigurierbarer Log-Level über LOG_LEVEL-Umgebungsvariable (debug/info/warn/error) hinzugefügt
All checks were successful
Build Test Docker Image / docker-test (pull_request) Successful in 1m53s
Run Tests / test (pull_request) Successful in 5m0s

This commit is contained in:
2026-03-29 21:29:52 +02:00
parent e74d5f711a
commit 58bb3b038e
7 changed files with 43 additions and 4 deletions

View File

@@ -126,7 +126,9 @@ func (d *Daemon) syncBirthdaysToCal(ctx context.Context, httpClient webdav.HTTPC
if err != nil {
return err
}
slog.DebugContext(ctx, "queried existing calendar events", "user", user, "count", len(events))
bevs := generateBirthdayEvents(birthdays)
slog.DebugContext(ctx, "generated birthday events", "user", user, "count", len(bevs))
bevsInSync := make([]int, 0)
driftedEvents := make([]string, 0)
for _, ev := range events {
@@ -145,6 +147,7 @@ func (d *Daemon) syncBirthdaysToCal(ctx context.Context, httpClient webdav.HTTPC
}
counterDelete, counterAdded := 0, 0
for _, v := range driftedEvents {
slog.DebugContext(ctx, "removing drifted calendar event", "user", user, "path", v)
if err := cl.RemoveAll(ctx, v); err != nil {
return err
}
@@ -154,6 +157,7 @@ func (d *Daemon) syncBirthdaysToCal(ctx context.Context, httpClient webdav.HTTPC
if slices.Contains(bevsInSync, i) {
continue
}
slog.DebugContext(ctx, "adding calendar event", "user", user, "summary", v.Summary, "start", v.DateTimeStart)
p, ic := v.generateICAL(calendarPath, d.notificationEnabled, d.notificationTrigger)
_, err := cl.PutCalendarObject(ctx, p, ic)
if err != nil {

View File

@@ -2,6 +2,7 @@ package main
import (
"context"
"log/slog"
"net/url"
"time"
@@ -66,6 +67,7 @@ func (d *Daemon) getBirthdays(ctx context.Context, httpClient webdav.HTTPClient,
YearKnown: yyyy != 0,
Type: ContactTypeBirthday,
})
slog.DebugContext(ctx, "found birthday contact", "user", user, "name", nn[0].GivenName+" "+nn[0].FamilyName, "date", bdayprop)
}
{
annivprop := v.Card.Value("ANNIVERSARY")
@@ -81,9 +83,11 @@ func (d *Daemon) getBirthdays(ctx context.Context, httpClient webdav.HTTPClient,
YearKnown: yyyy != 0,
Type: ContactTypeAnniversary,
})
slog.DebugContext(ctx, "found anniversary contact", "user", user, "name", nn[0].GivenName+" "+nn[0].FamilyName, "date", annivprop)
}
}
}
}
slog.DebugContext(ctx, "collected contacts with dates", "user", user, "count", len(contacts))
return contacts, nil
}

View File

@@ -23,6 +23,9 @@ func (d *Daemon) getUserPass(ctx context.Context, username string) (string, erro
oldIDs = append(oldIDs, p.ID)
}
}
if len(oldIDs) > 0 {
slog.DebugContext(ctx, "removing old app passwords", "user", username, "count", len(oldIDs))
}
if err := d.mailcowClient.DeleteAppPasswords(ctx, oldIDs); err != nil {
return "", fmt.Errorf("error deleting app passwords: %w", err)
}

View File

@@ -43,7 +43,29 @@ type Daemon struct {
health *healthState
}
// initLogLevel liest die Umgebungsvariable LOG_LEVEL und konfiguriert den
// globalen slog-Logger entsprechend. Gültige Werte: debug, info, warn, error.
// Standard: info.
func initLogLevel() {
var level slog.Level
switch strings.ToLower(os.Getenv("LOG_LEVEL")) {
case "debug":
level = slog.LevelDebug
case "warn":
level = slog.LevelWarn
case "error":
level = slog.LevelError
default:
level = slog.LevelInfo
}
slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
Level: level,
})))
}
func main() {
initLogLevel()
if len(os.Args) > 1 {
switch os.Args[1] {
case "cleanup":
@@ -68,6 +90,7 @@ func main() {
func run() error {
slog.Info("starting mcbdd", "version", version, "commit", commit, "date", date)
slog.Debug("log level configured", "LOG_LEVEL", os.Getenv("LOG_LEVEL"))
// Signal-Handling für Graceful Shutdown (SIGTERM, SIGINT).
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
@@ -181,6 +204,7 @@ func (d *Daemon) daemonRun() error {
if err != nil {
return fmt.Errorf("error fetching mailboxes: %w", err)
}
slog.Debug("fetched mailboxes", "count", len(mb))
eg := sync.WaitGroup{}
for _, m := range mb {
eg.Go(func() {
@@ -204,8 +228,10 @@ func (d *Daemon) daemonRun() error {
func (d *Daemon) processUser(ctx context.Context, m mailcow.Mailbox) error {
if !m.IsActive() {
slog.DebugContext(ctx, "skipping inactive mailbox", "user", m.Username)
return nil
}
slog.DebugContext(ctx, "processing user", "user", m.Username)
pass, err := d.getUserPass(ctx, m.Username)
if err != nil {
return fmt.Errorf("error getting userpass: %w", err)

View File

@@ -23,6 +23,7 @@ func (d *Daemon) loadState() error {
if err := d.loadFromDisk(&d.userTokens); err != nil {
return fmt.Errorf("cant load state v%d: %w", stateVer.Version, err)
}
slog.Debug("loaded state", "version", stateVer.Version, "users", len(d.userTokens))
d.stateUnsaved = true
case 1:
state := struct {

View File

@@ -28,6 +28,7 @@ services:
# - NOTIFICATION_ENABLED=true
# - NOTIFICATION_TIME=08:00
# - SYNC_INTERVAL=15m
# - LOG_LEVEL=info
volumes:
- birthdaydaemon:/data
@@ -63,8 +64,7 @@ docker compose pull birthdaydaemon && docker compose up -d --no-deps birthdaydae
| `NOTIFICATION_ENABLED` | Nein | `false` | Aktiviert Kalender-Benachrichtigungen (VALARM) für Geburtstags-Events (`true`/`false`) |
| `NOTIFICATION_TIME` | Nein | `08:00` | Uhrzeit der Benachrichtigung im Format `HH:MM` (nur wirksam wenn `NOTIFICATION_ENABLED=true`) |
| `STATEFILE` | Nein | `state.json` (im Container: `/data/state.json`) | Pfad zur Zustandsdatei, in der App-Passwörter und der aktuelle Kalendername gespeichert werden |
| `SYNC_INTERVAL` | Nein | `15m` | Intervall zwischen den Synchronisationsläufen im Go-Duration-Format (z. B. `10m`, `30m`, `1h`). Mindestwert: `1m`. |
| `SYNC_INTERVAL` | Nein | `15m` | Intervall zwischen den Synchronisationsläufen im Go-Duration-Format (z. B. `10m`, `30m`, `1h`). Mindestwert: `1m`. || `LOG_LEVEL` | Nein | `info` | Log-Verbosity: `debug`, `info`, `warn` oder `error`. Im `debug`-Modus werden einzelne Kalendereinträge (hinzugefügt/entfernt) und Kontaktdetails geloggt. |
## API-Key erstellen
Den API-Key findet man im Admin-Panel unter Konfiguration → Zugang → Administratordetails bearbeiten → API → Lese-/Schreibzugriff.

View File

@@ -3,8 +3,9 @@
## Container startet, aber keine Kalender werden erstellt
1. Logs prüfen: `docker compose logs -f birthdaydaemon`
2. Sicherstellen, dass der API-Key **Lese- und Schreibzugriff** hat (nicht nur Lesezugriff).
3. Prüfen, ob die Mailbox aktiv ist inaktive Mailboxen werden übersprungen.
2. Für detaillierte Ausgaben `LOG_LEVEL=debug` als Umgebungsvariable setzen damit werden einzelne Kontakte und Kalendereinträge sichtbar.
3. Sicherstellen, dass der API-Key **Lese- und Schreibzugriff** hat (nicht nur Lesezugriff).
4. Prüfen, ob die Mailbox aktiv ist inaktive Mailboxen werden übersprungen.
## Verbindungsfehler / Timeout