1- import atexit
21import logging
3- import os
4- import threading
52
63from logging .config import dictConfig
74from pathlib import Path
85from sys import stdout
96
10- import requests
11-
127from dotenv import load_dotenv
138
149from memos import settings
15- from memos .api .context .context import get_current_trace_id
16- from memos .api .context .context_thread import ContextThreadPoolExecutor
10+ from memos .api .context .context import generate_trace_id , get_current_trace_id
1711
1812
1913# Load environment variables
@@ -39,95 +33,12 @@ class TraceIDFilter(logging.Filter):
3933 def filter (self , record ):
4034 try :
4135 trace_id = get_current_trace_id ()
42- record .trace_id = trace_id if trace_id else "no-trace-id"
36+ record .trace_id = trace_id if trace_id else generate_trace_id ()
4337 except Exception :
44- record .trace_id = "no-trace-id"
38+ record .trace_id = generate_trace_id ()
4539 return True
4640
4741
48- class CustomLoggerRequestHandler (logging .Handler ):
49- _instance = None
50- _lock = threading .Lock ()
51-
52- def __new__ (cls ):
53- if cls ._instance is None :
54- with cls ._lock :
55- if cls ._instance is None :
56- cls ._instance = super ().__new__ (cls )
57- cls ._instance ._initialized = False
58- cls ._instance ._executor = None
59- cls ._instance ._session = None
60- cls ._instance ._is_shutting_down = None
61- return cls ._instance
62-
63- def __init__ (self ):
64- """Initialize handler with minimal setup"""
65- if not self ._initialized :
66- super ().__init__ ()
67- workers = int (os .getenv ("CUSTOM_LOGGER_WORKERS" , "2" ))
68- self ._executor = ContextThreadPoolExecutor (
69- max_workers = workers , thread_name_prefix = "log_sender"
70- )
71- self ._is_shutting_down = threading .Event ()
72- self ._session = requests .Session ()
73- self ._initialized = True
74- atexit .register (self ._cleanup )
75-
76- def emit (self , record ):
77- """Process log records of INFO or ERROR level (non-blocking)"""
78- if os .getenv ("CUSTOM_LOGGER_URL" ) is None or self ._is_shutting_down .is_set ():
79- return
80-
81- try :
82- trace_id = get_current_trace_id () or "no-trace-id"
83- self ._executor .submit (self ._send_log_sync , record .getMessage (), trace_id )
84- except Exception as e :
85- if not self ._is_shutting_down .is_set ():
86- print (f"Error sending log: { e } " )
87-
88- def _send_log_sync (self , message , trace_id ):
89- """Send log message synchronously in a separate thread"""
90- try :
91- logger_url = os .getenv ("CUSTOM_LOGGER_URL" )
92- token = os .getenv ("CUSTOM_LOGGER_TOKEN" )
93-
94- headers = {"Content-Type" : "application/json" }
95- post_content = {"message" : message , "trace_id" : trace_id }
96-
97- # Add auth token if exists
98- if token :
99- headers ["Authorization" ] = f"Bearer { token } "
100-
101- # Add traceId to headers for consistency
102- headers ["traceId" ] = trace_id
103-
104- # Add custom attributes from env
105- for key , value in os .environ .items ():
106- if key .startswith ("CUSTOM_LOGGER_ATTRIBUTE_" ):
107- attribute_key = key [len ("CUSTOM_LOGGER_ATTRIBUTE_" ) :].lower ()
108- post_content [attribute_key ] = value
109-
110- self ._session .post (logger_url , headers = headers , json = post_content , timeout = 5 )
111- except Exception :
112- # Silently ignore errors to avoid affecting main application
113- pass
114-
115- def _cleanup (self ):
116- """Clean up resources during program exit"""
117- if not self ._initialized :
118- return
119-
120- self ._is_shutting_down .set ()
121- try :
122- self ._executor .shutdown (wait = False )
123- self ._session .close ()
124- except Exception as e :
125- print (f"Error during cleanup: { e } " )
126-
127- def close (self ):
128- """Override close to prevent premature shutdown"""
129-
130-
13142LOGGING_CONFIG = {
13243 "version" : 1 ,
13344 "disable_existing_loggers" : False ,
@@ -151,7 +62,7 @@ def close(self):
15162 "level" : selected_log_level ,
15263 "class" : "logging.StreamHandler" ,
15364 "stream" : stdout ,
154- "formatter" : "simplified " ,
65+ "formatter" : "no_datetime " ,
15566 "filters" : ["package_tree_filter" , "trace_id_filter" ],
15667 },
15768 "file" : {
@@ -160,18 +71,13 @@ def close(self):
16071 "filename" : _setup_logfile (),
16172 "maxBytes" : 1024 ** 2 * 10 ,
16273 "backupCount" : 10 ,
163- "formatter" : "simplified " ,
74+ "formatter" : "standard " ,
16475 "filters" : ["trace_id_filter" ],
16576 },
166- "custom_logger" : {
167- "level" : selected_log_level ,
168- "class" : "memos.log.CustomLoggerRequestHandler" ,
169- "formatter" : "simplified" ,
170- },
17177 },
17278 "root" : { # Root logger handles all logs
173- "level" : selected_log_level ,
174- "handlers" : ["console" , "file" , "custom_logger" ],
79+ "level" : logging . DEBUG if settings . DEBUG else logging . INFO ,
80+ "handlers" : ["console" , "file" ],
17581 },
17682 "loggers" : {
17783 "memos" : {
0 commit comments