11import enum
2- import functools
32
43import sentry_sdk
54from sentry_sdk .integrations import Integration , DidNotEnable
65from sentry_sdk .integrations .logging import (
76 BreadcrumbHandler ,
87 EventHandler ,
9- SentryLogsHandler ,
108 _BaseHandler ,
119 _python_level_to_otel ,
1210)
1513
1614if TYPE_CHECKING :
1715 from logging import LogRecord
18- from typing import Optional , Any
16+ from typing import Optional , Any , Tuple
1917
2018try :
2119 import loguru
2220 from loguru import logger
2321 from loguru ._defaults import LOGURU_FORMAT as DEFAULT_FORMAT
24- from loguru ._logger import Logger
2522except ImportError :
2623 raise DidNotEnable ("LOGURU is not installed" )
2724
@@ -36,6 +33,10 @@ class LoggingLevels(enum.IntEnum):
3633 CRITICAL = 50
3734
3835
36+ DEFAULT_LEVEL = LoggingLevels .INFO .value
37+ DEFAULT_EVENT_LEVEL = LoggingLevels .ERROR .value
38+
39+
3940SENTRY_LEVEL_FROM_LOGURU_LEVEL = {
4041 "TRACE" : "DEBUG" ,
4142 "DEBUG" : "DEBUG" ,
@@ -46,8 +47,22 @@ class LoggingLevels(enum.IntEnum):
4647 "CRITICAL" : "CRITICAL" ,
4748}
4849
49- DEFAULT_LEVEL = LoggingLevels .INFO .value
50- DEFAULT_EVENT_LEVEL = LoggingLevels .ERROR .value
50+
51+ def _loguru_level_to_otel (record_level ):
52+ # type: (int) -> Tuple[int, str]
53+ for py_level , otel_severity_number , otel_severity_text in [
54+ (LoggingLevels .CRITICAL , 21 , "fatal" ),
55+ (LoggingLevels .ERROR , 17 , "error" ),
56+ (LoggingLevels .WARNING , 13 , "warn" ),
57+ (LoggingLevels .SUCCESS , 11 , "info" ),
58+ (LoggingLevels .INFO , 9 , "info" ),
59+ (LoggingLevels .DEBUG , 5 , "debug" ),
60+ (LoggingLevels .TRACE , 1 , "trace" ),
61+ ]:
62+ if record_level >= py_level :
63+ return otel_severity_number , otel_severity_text
64+
65+ return 0 , "default"
5166
5267
5368class LoguruIntegration (Integration ):
@@ -91,24 +106,10 @@ def setup_once():
91106 )
92107
93108 if LoguruIntegration .sentry_logs_level is not None :
94- #logger.add(
95- # LoguruSentryLogsHandler(level=LoguruIntegration.sentry_logs_level),
96- # level=LoguruIntegration.sentry_logs_level,
97- # format=LoguruIntegration.event_format,
98- #)
99-
100- original_log = Logger ._log
101-
102- @functools .wraps (original_log )
103- def _sentry_patched_log (self , * args , ** kwargs ):
104- print ('hello from senry patched' )
105- log_args = args [4 ]
106- if log_args :
107- pass
108- result = original_log (self , * args , ** kwargs )
109- return result
110-
111- Logger ._log = _sentry_patched_log
109+ logger .add (
110+ loguru_sentry_logs_handler ,
111+ level = LoguruIntegration .sentry_logs_level ,
112+ )
112113
113114
114115class _LoguruBaseHandler (_BaseHandler ):
@@ -133,62 +134,73 @@ def _logging_to_event_level(self, record):
133134
134135class LoguruEventHandler (_LoguruBaseHandler , EventHandler ):
135136 """Modified version of :class:`sentry_sdk.integrations.logging.EventHandler` to use loguru's level names."""
137+
136138 pass
137139
138140
139141class LoguruBreadcrumbHandler (_LoguruBaseHandler , BreadcrumbHandler ):
140142 """Modified version of :class:`sentry_sdk.integrations.logging.BreadcrumbHandler` to use loguru's level names."""
143+
141144 pass
142145
143146
144- def _loguru_level_to_otel (record_level ):
145- # type: (int) -> Tuple[int, str]
146- for py_level , otel_severity_number , otel_severity_text in [
147- (50 , 21 , "fatal" ),
148- (40 , 17 , "error" ),
149- (30 , 13 , "warn" ),
150- (25 , 11 , "info" ), # Loguru's success
151- (20 , 9 , "info" ),
152- (10 , 5 , "debug" ),
153- (5 , 1 , "trace" ),
154- ]:
155- if record_level >= py_level :
156- return otel_severity_number , otel_severity_text
157- return 0 , "default"
147+ def loguru_sentry_logs_handler (message ):
148+ client = sentry_sdk .get_client ()
149+
150+ if not client .is_active ():
151+ return
152+
153+ if not client .options ["_experiments" ].get ("enable_logs" , False ):
154+ return
155+
156+ record = message .record
157+
158+ if record ["level" ].no < LoguruIntegration .sentry_logs_level :
159+ return
160+
161+ scope = sentry_sdk .get_current_scope ()
158162
163+ otel_severity_number , otel_severity_text = _python_level_to_otel (record ["level" ].no )
159164
160- class LoguruSentryLogsHandler (_LoguruBaseHandler ):
161- """Modified version of :class:`sentry_sdk.integrations.logging.SentryLogsHandler` to use loguru's level names."""
162- def emit (self , record ):
163- client = sentry_sdk .get_client ()
165+ attrs = {
166+ "sentry.origin" : "auto.logger.loguru" ,
167+ }
164168
165- if not client .is_active ():
166- return
169+ project_root = client .options ["project_root" ]
170+ if record .get ("file" ):
171+ if project_root is not None and record ["file" ].path .startswith (project_root ):
172+ attrs ["code.file.path" ] = record ["file" ].path
173+ else :
174+ attrs ["code.file.path" ] = record ["file" ].path
167175
168- if not client . options [ "_experiments" ]. get ("enable_logs" , False ) :
169- return
176+ if record . get ("line" ) is not None :
177+ attrs [ "code.line.number" ] = record [ "line" ]
170178
171- print ( 'rec' , record )
172- print ( 'strofrec' , str ( record ))
179+ if record . get ( "function" ):
180+ attrs [ "code.function.name" ] = record [ "function" ]
173181
174- self ._capture_log_from_record (client , record )
182+ if record .get ("thread" ):
183+ attrs ["thread.name" ] = record ["thread" ].name
184+ attrs ["thread.id" ] = record ["thread" ].id
175185
176- def _capture_log_from_record ( self , client , record ):
177- # type: (BaseClient, LogRecord)
178- scope = sentry_sdk . get_current_scope ()
186+ if record . get ( "process" ):
187+ attrs [ "process.pid" ] = record [ "process" ]. id
188+ attrs [ "process.executable.name" ] = record [ "process" ]. name
179189
180- otel_severity_number , otel_severity_text = _python_level_to_otel (record .levelno )
190+ if record .get ("name" ):
191+ attrs ["logger.name" ] = record ["name" ]
181192
182- attrs = {}
193+ if record ["message" ]:
194+ attrs ["sentry.message.template" ] = record ["message" ]
183195
184- client ._capture_experimental_log (
185- scope ,
186- {
187- "severity_text" : otel_severity_text ,
188- "severity_number" : otel_severity_number ,
189- "body" : record . msg ,
190- "attributes" : attrs ,
191- "time_unix_nano" : int (record . created * 1e9 ),
192- "trace_id" : None ,
193- },
194- )
196+ client ._capture_experimental_log (
197+ scope ,
198+ {
199+ "severity_text" : otel_severity_text ,
200+ "severity_number" : otel_severity_number ,
201+ "body" : record [ "message" ] ,
202+ "attributes" : attrs ,
203+ "time_unix_nano" : int (record [ "time" ]. timestamp () * 1e9 ),
204+ "trace_id" : None ,
205+ },
206+ )
0 commit comments