@@ -145,7 +145,7 @@ def formatTime(self, record, datefmt=None):
145145
146146@_singleton
147147class WeaveStack (object ):
148- def __init__ (self ):
148+ def __init__ (self , installDefaultLogHandler = True ):
149149 self .networkLock = Lock ()
150150 self .completeEvent = Event ()
151151 self ._weaveStackLib = None
@@ -157,28 +157,49 @@ def __init__(self):
157157 # Locate and load the openweave shared library.
158158 self ._loadLib ()
159159
160- # By default, configure the openweave library to log to a python logger object with the
161- # name 'openweave.WeaveStack'. If this logger has not already been initialized by
162- # the application, automatically configure it to log to stdout.
160+ # Arrange to log output from the openweave library to a python logger object with the
161+ # name 'openweave.WeaveStack'. If desired, applications can override this behavior by
162+ # setting self.logger to a different python logger object, or by calling setLogFunct()
163+ # with their own logging function.
164+ self .logger = logging .getLogger (__name__ )
165+ self .setLogFunct (self .defaultLogFunct )
166+
167+ # Determine if there are already handlers installed for the logger. Python 3.5+
168+ # has a method for this; on older versions the check has to be done manually.
169+ if hasattr (self .logger , 'hasHandlers' ):
170+ hasHandlers = self .logger .hasHandlers ()
171+ else :
172+ hasHandlers = False
173+ logger = self .logger
174+ while logger is not None :
175+ if len (logger .handlers ) > 0 :
176+ hasHandlers = True
177+ break
178+ if not logger .propagate :
179+ break
180+ logger = logger .parent
181+
182+ # If a logging handler has not already been initialized for 'openweave.WeaveStack',
183+ # or any one of its parent loggers, automatically configure a handler to log to
184+ # stdout. This maintains compatibility with a number of applications which expect
185+ # openweave log output to go to stdout by default.
163186 #
164- # Applications can override this behavior in any one the following ways:
165- # - Setting self.logger to a different python logger object .
166- # - Replacing the StreamHandler on self.logger with a different handler object .
167- # - Setting a different Formatter object on the existing StreamHandler object.
168- # - Reconfiguring the existing LogMessageFormatter object, e.g. to enable logging
169- # of timestamps .
170- # - Configuring openwave to call an application-specific logging function by
187+ # This behavior can be overridden in a variety of ways:
188+ # - Initialize a different log handler before WeaveStack is initialized .
189+ # - Pass installDefaultLogHandler=False when initializing WeaveStack .
190+ # - Replace the StreamHandler on self.logger with a different handler object.
191+ # - Set a different Formatter object on the existing StreamHandler object.
192+ # - Reconfigure the existing WeaveLogFormatter object .
193+ # - Configure openweave to call an application-specific logging function by
171194 # calling self.setLogFunct().
172- # - Calling self.setLogFunct(None), which will configure the openweave library
195+ # - Call self.setLogFunct(None), which will configure the openweave library
173196 # to log directly to stdout, bypassing python altogether.
174197 #
175- self .logger = logging .getLogger (__name__ )
176- if len (self .logger .handlers ) == 0 :
198+ if installDefaultLogHandler and not hasHandlers :
177199 logHandler = logging .StreamHandler (stream = sys .stdout )
178200 logHandler .setFormatter (WeaveLogFormatter ())
179201 self .logger .addHandler (logHandler )
180202 self .logger .setLevel (logging .DEBUG )
181- self .setLogFunct (self .defaultLogFunct )
182203
183204 def HandleComplete (appState , reqState ):
184205 self .callbackRes = True
0 commit comments