1616#
1717
1818import logging
19- import sys
2019import traceback
21- from multiprocessing import current_process
22- from os .path import basename , splitext
23- from threading import current_thread
2420
2521from skywalking import config
2622from skywalking .agent import agent
3329link_vector = ['https://pypi.org/project/loguru/' ]
3430support_matrix = {
3531 'loguru' : {
36- '>=3.7' : ['0.6.0' ]
32+ '>=3.7' : ['0.6.0' , '0.7.0' ]
3733 }
3834}
3935note = """"""
4036
4137
4238def install ():
39+ if not config .agent_log_reporter_active :
40+ return
41+
4342 from loguru import logger
44- from loguru ._recattrs import RecordException , RecordFile , RecordLevel , RecordProcess , RecordThread
45- from loguru ._datetime import aware_now
46- from loguru ._get_frame import get_frame
47- from loguru ._logger import start_time , context as logger_context , Logger
48- from types import MethodType
4943
50- _log = logger ._log
5144 log_reporter_level = logging .getLevelName (config .agent_log_reporter_level ) # type: int
5245
53- def gen_record (self , level_id , static_level_no , from_decorator , options , message , args , kwargs ):
54- """ Generate log record as loguru.logger._log """
55- core = self ._core
56-
57- if not core .handlers :
58- return
59-
60- (exception , depth , record , lazy , colors , raw , capture , patcher , extra ) = options
46+ def _sw_sink (message ):
47+ record = message .record
6148
62- frame = get_frame (depth + 2 )
63-
64- try :
65- name = frame .f_globals ['__name__' ]
66- except KeyError :
67- name = None
68-
69- try :
70- if not core .enabled [name ]:
71- return
72- except KeyError :
73- enabled = core .enabled
74- if name is None :
75- status = core .activation_none
76- enabled [name ] = status
77- if not status :
78- return
79- else :
80- dotted_name = name + '.'
81- for dotted_module_name , status in core .activation_list :
82- if dotted_name [: len (dotted_module_name )] == dotted_module_name :
83- if status :
84- break
85- enabled [name ] = False
86- return
87- enabled [name ] = True
88-
89- current_datetime = aware_now ()
90-
91- if level_id is None :
92- level_icon = ' '
93- level_no = static_level_no
94- level_name = f'Level { level_no } ' # not really level name, just as loguru
95- else :
96- level_name , level_no , _ , level_icon = core .levels [level_id ]
97-
98- if level_no < core .min_level :
99- return
100-
101- code = frame .f_code
102- file_path = code .co_filename
103- file_name = basename (file_path )
104- thread = current_thread ()
105- process = current_process ()
106- elapsed = current_datetime - start_time
107-
108- if exception :
109- if isinstance (exception , BaseException ):
110- type_ , value , traceback = (type (exception ), exception , exception .__traceback__ )
111- elif isinstance (exception , tuple ):
112- type_ , value , traceback = exception
113- else :
114- type_ , value , traceback = sys .exc_info ()
115- exception = RecordException (type_ , value , traceback )
116- else :
117- exception = None
118-
119- log_record = {
120- 'elapsed' : elapsed ,
121- 'exception' : exception ,
122- 'extra' : {** core .extra , ** logger_context .get (), ** extra },
123- 'file' : RecordFile (file_name , file_path ),
124- 'function' : code .co_name ,
125- 'level' : RecordLevel (level_name , level_no , level_icon ),
126- 'line' : frame .f_lineno ,
127- 'message' : str (message ),
128- 'module' : splitext (file_name )[0 ],
129- 'name' : name ,
130- 'process' : RecordProcess (process .ident , process .name ),
131- 'thread' : RecordThread (thread .ident , thread .name ),
132- 'time' : current_datetime ,
133- }
134-
135- if capture and kwargs :
136- log_record ['extra' ].update (kwargs )
137-
138- if record :
139- kwargs .update (record = log_record )
140-
141- if args or kwargs :
142- log_record ['message' ] = message .format (* args , ** kwargs )
143-
144- if core .patcher :
145- core .patcher (log_record )
146-
147- if patcher :
148- patcher (log_record )
149-
150- return log_record
151-
152- def _sw_log (self , level_id , static_level_no , from_decorator , options , message , args , kwargs ):
153- _log (level_id , static_level_no , from_decorator , options , message , args , kwargs )
154- record = gen_record (self , level_id , static_level_no , from_decorator , options , message , args , kwargs )
15549 if record is None :
15650 return
15751
158- core = self ._core
159-
16052 if record ['level' ].no < log_reporter_level :
16153 return
16254
163- if not config .agent_log_reporter_ignore_filter and record ['level' ].no < core .min_level : # ignore filtered logs
164- return
165-
16655 # loguru has only one logger. Use tags referring Python-Agent doc
16756 core_tags = [
16857 KeyStringValuePair (key = 'level' , value = record ['level' ].name ),
@@ -202,7 +91,7 @@ def _sw_log(self, level_id, static_level_no, from_decorator, options, message, a
20291 body = LogDataBody (
20392 type = 'text' ,
20493 text = TextLog (
205- text = sw_filter (message )
94+ text = sw_filter (record [ ' message' ] )
20695 )
20796 ),
20897 tags = tags ,
@@ -221,8 +110,5 @@ def _sw_log(self, level_id, static_level_no, from_decorator, options, message, a
221110
222111 agent .archive_log (log_data )
223112
224- # Bind _sw_log function to default logger instance.
225- bound_sw_log = MethodType (_sw_log , logger )
226- logger ._log = bound_sw_log
227- # Bind _sw_log function to Logger class for new instance.
228- Logger ._log = _sw_log
113+ # Make sure any logged message by loguru is also sent to skywalking OAP
114+ logger .add (_sw_sink )
0 commit comments