44 "flag"
55 "fmt"
66 "os"
7+ "os/signal"
78 "strings"
9+ "syscall"
810 "time"
911
1012 "github.com/JohanDevl/Export_Trakt_4_Letterboxd/pkg/api"
@@ -289,10 +291,18 @@ func exportWatchlist(client *api.Client, exporter *export.LetterboxdExporter, lo
289291
290292// runExportOnce executes the export once and then exits
291293func runExportOnce (cfg * config.Config , log logger.Logger , translator * i18n.Translator , exportType , exportMode string ) {
294+ log .Info ("export.starting_execution" , map [string ]interface {}{
295+ "export_type" : exportType ,
296+ "export_mode" : exportMode ,
297+ "timestamp" : time .Now ().Format (time .RFC3339 ),
298+ })
299+
292300 // Initialize Trakt client
301+ log .Info ("export.initializing_trakt_client" , nil )
293302 traktClient := api .NewClient (cfg , log )
294303
295304 // Initialize Letterboxd exporter
305+ log .Info ("export.initializing_letterboxd_exporter" , nil )
296306 letterboxdExporter := export .NewLetterboxdExporter (cfg , log )
297307
298308 // Log export mode
@@ -301,18 +311,28 @@ func runExportOnce(cfg *config.Config, log logger.Logger, translator *i18n.Trans
301311 })
302312
303313 // Perform the export based on type
314+ log .Info ("export.starting_data_retrieval" , map [string ]interface {}{
315+ "export_type" : exportType ,
316+ })
317+
304318 switch exportType {
305319 case "watched" :
320+ log .Info ("export.executing_watched_movies" , nil )
306321 exportWatchedMovies (traktClient , letterboxdExporter , log )
307322 case "collection" :
323+ log .Info ("export.executing_collection" , nil )
308324 exportCollection (traktClient , letterboxdExporter , log )
309325 case "shows" :
326+ log .Info ("export.executing_shows" , nil )
310327 exportShows (traktClient , letterboxdExporter , log )
311328 case "ratings" :
329+ log .Info ("export.executing_ratings" , nil )
312330 exportRatings (traktClient , letterboxdExporter , log )
313331 case "watchlist" :
332+ log .Info ("export.executing_watchlist" , nil )
314333 exportWatchlist (traktClient , letterboxdExporter , log )
315334 case "all" :
335+ log .Info ("export.executing_all_types" , nil )
316336 exportWatchedMovies (traktClient , letterboxdExporter , log )
317337 exportCollection (traktClient , letterboxdExporter , log )
318338 exportShows (traktClient , letterboxdExporter , log )
@@ -327,11 +347,32 @@ func runExportOnce(cfg *config.Config, log logger.Logger, translator *i18n.Trans
327347 log .Info ("export.completed_successfully" , map [string ]interface {}{
328348 "export_type" : exportType ,
329349 "export_mode" : exportMode ,
350+ "timestamp" : time .Now ().Format (time .RFC3339 ),
330351 })
331352}
332353
333354// runWithSchedule sets up a cron scheduler and runs the export according to the schedule
334355func runWithSchedule (cfg * config.Config , log logger.Logger , translator * i18n.Translator , schedule , exportType , exportMode string ) {
356+ log .Info ("scheduler.initializing" , map [string ]interface {}{
357+ "schedule" : schedule ,
358+ "export_type" : exportType ,
359+ "export_mode" : exportMode ,
360+ })
361+
362+ // Check for verbose logging environment variable
363+ if os .Getenv ("EXPORT_VERBOSE" ) == "true" {
364+ log .SetLogLevel ("debug" )
365+ log .Info ("scheduler.verbose_mode_enabled" , nil )
366+ }
367+
368+ // Override log level if LOG_LEVEL environment variable is set
369+ if logLevel := os .Getenv ("LOG_LEVEL" ); logLevel != "" {
370+ log .SetLogLevel (logLevel )
371+ log .Info ("scheduler.log_level_set" , map [string ]interface {}{
372+ "level" : logLevel ,
373+ })
374+ }
375+
335376 // Validate cron expression
336377 cronParser := cron .NewParser (cron .Minute | cron .Hour | cron .Dom | cron .Month | cron .Dow )
337378 _ , err := cronParser .Parse (schedule )
@@ -348,19 +389,38 @@ func runWithSchedule(cfg *config.Config, log logger.Logger, translator *i18n.Tra
348389 os .Exit (1 )
349390 }
350391
392+ log .Info ("scheduler.cron_validation_successful" , map [string ]interface {}{
393+ "schedule" : schedule ,
394+ })
395+
351396 // Create a new cron scheduler
352397 c := cron .New ()
353398
354399 // Add the export job to the scheduler
355400 entryID , err := c .AddFunc (schedule , func () {
356- log .Info ("scheduler.executing_export " , map [string ]interface {}{
401+ log .Info ("scheduler.job_triggered " , map [string ]interface {}{
357402 "schedule" : schedule ,
358403 "export_type" : exportType ,
359404 "export_mode" : exportMode ,
405+ "timestamp" : time .Now ().Format (time .RFC3339 ),
360406 })
361407
362- // Run the export
408+ // Run the export with additional logging
409+ log .Info ("scheduler.starting_export_execution" , map [string ]interface {}{
410+ "export_type" : exportType ,
411+ "export_mode" : exportMode ,
412+ })
413+
414+ startTime := time .Now ()
363415 runExportOnce (cfg , log , translator , exportType , exportMode )
416+ duration := time .Since (startTime )
417+
418+ log .Info ("scheduler.export_execution_completed" , map [string ]interface {}{
419+ "export_type" : exportType ,
420+ "export_mode" : exportMode ,
421+ "duration" : duration .String (),
422+ "next_run" : c .Entries ()[0 ].Next .Format (time .RFC3339 ),
423+ })
364424 })
365425
366426 if err != nil {
@@ -372,8 +432,14 @@ func runWithSchedule(cfg *config.Config, log logger.Logger, translator *i18n.Tra
372432 os .Exit (1 )
373433 }
374434
435+ log .Info ("scheduler.job_added_successfully" , map [string ]interface {}{
436+ "entry_id" : entryID ,
437+ "schedule" : schedule ,
438+ })
439+
375440 // Start the cron scheduler
376441 c .Start ()
442+ log .Info ("scheduler.cron_started" , nil )
377443
378444 // Get the next run time
379445 entries := c .Entries ()
@@ -390,14 +456,54 @@ func runWithSchedule(cfg *config.Config, log logger.Logger, translator *i18n.Tra
390456 fmt .Printf ("Export Type: %s\n " , exportType )
391457 fmt .Printf ("Export Mode: %s\n " , exportMode )
392458 fmt .Printf ("Next run: %s\n " , nextRun .Format ("2006-01-02 15:04:05 MST" ))
459+
460+ // Log upcoming executions for the next hour
461+ now := time .Now ()
462+ oneHourLater := now .Add (time .Hour )
463+ log .Info ("scheduler.upcoming_executions_preview" , map [string ]interface {}{
464+ "next_hour_from" : now .Format (time .RFC3339 ),
465+ "next_hour_to" : oneHourLater .Format (time .RFC3339 ),
466+ })
467+
468+ count := 0
469+ if len (entries ) > 0 {
470+ entry := entries [0 ]
471+ nextExec := entry .Next
472+ for nextExec .Before (oneHourLater ) && count < 10 {
473+ log .Info ("scheduler.upcoming_execution" , map [string ]interface {}{
474+ "execution_time" : nextExec .Format ("2006-01-02 15:04:05 MST" ),
475+ "in_minutes" : int (time .Until (nextExec ).Minutes ()),
476+ })
477+ // Calculate next execution after this one
478+ schedule , _ := cronParser .Parse (schedule )
479+ nextExec = schedule .Next (nextExec )
480+ count ++
481+ }
482+ }
393483 }
394484
395485 // Keep the program running until interrupted
396486 log .Info ("scheduler.waiting" , map [string ]interface {}{
397487 "message" : "Scheduler is running. Press Ctrl+C to stop." ,
488+ "pid" : os .Getpid (),
398489 })
399490 fmt .Println ("Scheduler is running. Press Ctrl+C to stop..." )
400491
492+ // Set up signal handling for graceful shutdown
493+ sigChan := make (chan os.Signal , 1 )
494+ signal .Notify (sigChan , syscall .SIGINT , syscall .SIGTERM )
495+
496+ go func () {
497+ sig := <- sigChan
498+ log .Info ("scheduler.shutdown_signal_received" , map [string ]interface {}{
499+ "signal" : sig .String (),
500+ })
501+ fmt .Printf ("\n Received signal %s, shutting down gracefully...\n " , sig )
502+ c .Stop ()
503+ log .Info ("scheduler.shutdown_complete" , nil )
504+ os .Exit (0 )
505+ }()
506+
401507 // Block forever (or until SIGINT/SIGTERM)
402508 select {}
403509}
0 commit comments