11import os
22from collections .abc import Callable
33from contextlib import contextmanager
4- from sys import stdout
54from time import perf_counter
65from time import sleep
6+ from time import time
77
88import schedule
99from dotenv import load_dotenv
1212from pyconfigparser import ConfigError , ConfigFileNotFoundError , configparser
1313
1414from config_schema import CONFIG_SCHEMA
15- from renamarr .observability import (
16- ServiceName ,
17- configure_observability ,
18- enrich_log_record_with_trace ,
19- is_otel_enabled ,
20- )
15+ from renamarr .logging_config import LoggingConfigurator
16+ from renamarr .observability import ServiceName , configure_observability
2117from renamarr .radarr .services .renamarr import RadarrRenamarr
2218from renamarr .sonarr .services .renamarr import SonarrRenamarr
2319from renamarr .sonarr .services .series_scanner import SonarrSeriesScanner
@@ -29,77 +25,13 @@ class Main:
2925 """
3026
3127 RUN_SCHEDULER = True
32- _LOG_FORMAT = (
33- "<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | "
34- "<level>{level}</level> | "
35- "{extra[instance]} | "
36- "{extra[item]} | "
37- "<level>{message}</level>"
38- )
39- _DEBUG_LOG_FORMAT = (
40- "<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | "
41- "<level>{level}</level> | "
42- "<cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> | "
43- "{extra[instance]} | "
44- "{extra[item]} | "
45- "<level>{message}</level>"
46- )
47- _TRACE_LOG_FORMAT = "trace_id={extra[trace_id]} | span_id={extra[span_id]} | "
4828
4929 def __init__ (self ):
5030 load_dotenv (".env.local" )
51- log_level = os .getenv ("LOG_LEVEL" , "INFO" )
52-
53- otel_enabled = is_otel_enabled ()
54- base_logger_format = (
55- self ._DEBUG_LOG_FORMAT if log_level .upper () == "DEBUG" else self ._LOG_FORMAT
56- )
57- self ._logger_format = (
58- base_logger_format .replace (
59- "<level>{message}</level>" ,
60- f"{ self ._TRACE_LOG_FORMAT } <level>{{message}}</level>" ,
61- )
62- if otel_enabled
63- else base_logger_format
64- )
65- log_extra = {"instance" : "" , "item" : "" }
66- if otel_enabled :
67- log_extra |= {"trace_id" : "" , "span_id" : "" }
68- logger .configure (
69- extra = log_extra ,
70- patcher = enrich_log_record_with_trace if otel_enabled else None ,
71- )
72- logger .remove ()
73- logger .add (stdout , format = self ._logger_format , level = log_level )
31+ self ._logging_configurator = LoggingConfigurator ()
32+ self ._logging_configurator .configure_stdout ()
7433 self .observability = configure_observability ()
7534
76- def __configure_file_logging (self , service : str , instance_name : str ) -> bool :
77- log_dir = os .getenv ("LOG_DIR" , "/logs" )
78- log_rotation = os .getenv ("LOG_ROTATION" , "00:00" )
79- log_retention = os .getenv ("LOG_RETENTION" , "7 days" )
80- log_path = os .path .join (log_dir , service , f"{ instance_name } .log" )
81- try :
82- logger .add (
83- log_path ,
84- format = self ._logger_format ,
85- level = os .getenv ("LOG_LEVEL" , "INFO" ),
86- rotation = log_rotation ,
87- retention = log_retention ,
88- # filter ensures that instance logs go to the correct file
89- filter = lambda record , configured_service = service , configured_name = instance_name : (
90- record ["extra" ].get ("service" ) == configured_service
91- and record ["extra" ].get ("instance" ) == configured_name
92- ),
93- )
94- except OSError as exc :
95- with logger .contextualize (service = service , instance = instance_name ):
96- logger .warning (
97- f"Unable to write logs to { log_path !r} ; continuing with stdout logging only."
98- )
99- logger .warning (exc )
100- return False
101- return True
102-
10335 def __external_cron (self ) -> bool :
10436 return os .getenv ("EXTERNAL_CRON" , "false" ).lower () == "true"
10537
@@ -111,6 +43,12 @@ def __run_observed_job(
11143 job : Callable [[], None ],
11244 ) -> None :
11345 start_time = perf_counter ()
46+ self .observability .record_job_started (
47+ service ,
48+ instance_name ,
49+ job_name ,
50+ time (),
51+ )
11452 result = "success"
11553 try :
11654 with self .observability .start_span (
@@ -125,6 +63,9 @@ def __run_observed_job(
12563 except CliArrError as exc :
12664 result = "failed"
12765 logger .error (exc )
66+ except Exception :
67+ result = "failed"
68+ raise
12869 finally :
12970 self .observability .record_job (
13071 service ,
@@ -246,13 +187,17 @@ def __start(self) -> None:
246187 self .__schedule_sonarr_series_scanner (sonarr_config )
247188 if sonarr_config .renamarr .enabled :
248189 if sonarr_config .renamarr .log_to_file :
249- self .__configure_file_logging ("sonarr" , sonarr_config .name )
190+ self ._logging_configurator .configure_instance_file (
191+ "sonarr" , sonarr_config .name
192+ )
250193 self .__schedule_sonarr_renamarr (sonarr_config )
251194
252195 for radarr_config in config .radarr :
253196 if radarr_config .renamarr .enabled :
254197 if radarr_config .renamarr .log_to_file :
255- self .__configure_file_logging ("radarr" , radarr_config .name )
198+ self ._logging_configurator .configure_instance_file (
199+ "radarr" , radarr_config .name
200+ )
256201 self .__schedule_radarr_renamarr (radarr_config )
257202 else :
258203 with logger .contextualize (instance = radarr_config .name ):
0 commit comments