def make_logger(log_level=None, logger=Logger, observer=log_publisher): """ Make a new logger (of the type set by the kwarg logger) that publishes to the observer set in the observer kwarg. If no explicit log_level is given, it uses the current global log level. """ # Get the caller's frame cf = currentframe(1) if "self" in cf.f_locals: # We're probably in a class init or method namespace = qual(cf.f_locals["self"].__class__) logger = CrossbarLogger(log_level, namespace=namespace, logger=logger, observer=observer) else: namespace = cf.f_globals["__name__"] if cf.f_code.co_name != "<module>": # If it's not the module, and not in a class instance, add the code # object's name. namespace = namespace + "." + cf.f_code.co_name logger = CrossbarLogger(log_level, namespace=namespace, logger=logger, observer=observer) # Set up a weak ref, so that all loggers can be updated later _loggers[logger] = True return logger
def _namespaceFromCallingContext(): """ Derive a namespace from the module containing the caller's caller. @return: the fully qualified python name of a module. @rtype: L{str} (native string) """ return currentframe(2).f_globals["__name__"]
def nextLine(): """ Retrive the file name and line number immediately after where this function is called. @return: the file name and line number @rtype: 2-L{tuple} of L{str}, L{int} """ caller = currentframe(1) return (getsourcefile(sys.modules[caller.f_globals['__name__']]), caller.f_lineno + 1)
def _namespaceFromCallingContext(): """ Derive a namespace from the module containing the caller's caller. @return: the fully qualified python name of a module. @rtype: L{str} (native string) """ try: return currentframe(2).f_globals["__name__"] except KeyError: return "<unknown>"
def nextLine() -> Tuple[Optional[str], int]: """ Retrive the file name and line number immediately after where this function is called. @return: the file name and line number """ caller = currentframe(1) return ( getsourcefile(sys.modules[caller.f_globals["__name__"]]), caller.f_lineno + 1, )
def getDataDirectory(moduleName=None): """ Get a data directory for the caller function, or C{moduleName} if given. @param moduleName: The module name if you don't wish to have the caller's module. @type moduleName: L{str} @returns: A directory for putting data in. @rtype: L{str} """ if not moduleName: caller = currentframe(1) moduleName = inspect.getmodule(caller).__name__ return appdirs.user_data_dir(moduleName)
def getDataDirectory(moduleName: str = "") -> str: """ Get a data directory for the caller function, or C{moduleName} if given. @param moduleName: The module name if you don't wish to have the caller's module. @returns: A directory for putting data in. """ if not moduleName: caller = currentframe(1) module = inspect.getmodule(caller) assert module is not None moduleName = module.__name__ return cast(str, appdirs.user_data_dir(moduleName))
def _findCaller(self, stackInfo: bool = False, stackLevel: int = 1) -> Tuple[str, int, str, None]: """ Based on the stack depth passed to this L{STDLibLogObserver}, identify the calling function. @param stackInfo: Whether or not to construct stack information. (Currently ignored.) @param stackLevel: The number of stack frames to skip when determining the caller (currently ignored; use stackDepth on the instance). @return: Depending on Python version, either a 3-tuple of (filename, lineno, name) or a 4-tuple of that plus stack information. """ f = currentframe(self.stackDepth) co = f.f_code extra = (None, ) return (co.co_filename, f.f_lineno, co.co_name) + extra
def _from_stack(cls, function=None): """ Should only be called by py:`LockableDatabase.transaction`. Find the caller of and construct an exception referencing it. This will skip over the wrapper from :py:`with_cursor`. This must be called on a subclass that defines `.message`. """ # There are 2 stack frames between this function # 0. _LockableDatabaseTransactionError.from_stack # 1. LockableDatabase.transaction # 2. contextlib.contextmanger's __enter__ # 3. Our caller (potentially with_cursor) frame = currentframe(3) if frame.f_code == with_cursor._wrapped_code: frame = frame.f_back caller = frame.f_code.co_name return cls(caller=caller, function=function)
def _findCaller(self, stackInfo=False): """ Based on the stack depth passed to this L{STDLibLogObserver}, identify the calling function. @param stackInfo: Whether or not to construct stack information. (Currently ignored.) @type stackInfo: L{bool} @return: Depending on Python version, either a 3-tuple of (filename, lineno, name) or a 4-tuple of that plus stack information. @rtype: L{tuple} """ f = currentframe(self.stackDepth) co = f.f_code if _PY3: extra = (None, ) else: extra = () return (co.co_filename, f.f_lineno, co.co_name) + extra
def _findCaller(self, stackInfo=False): """ Based on the stack depth passed to this L{STDLibLogObserver}, identify the calling function. @param stackInfo: Whether or not to construct stack information. (Currently ignored.) @type stackInfo: L{bool} @return: Depending on Python version, either a 3-tuple of (filename, lineno, name) or a 4-tuple of that plus stack information. @rtype: L{tuple} """ f = currentframe(self.stackDepth) co = f.f_code if _PY3: extra = (None,) else: extra = () return (co.co_filename, f.f_lineno, co.co_name) + extra
def beginLoggingTo( self, observers, discardBuffer=False, redirectStandardIO=True ): """ Begin logging to the given set of observers. This will: 1. Add all the observers given in C{observers} to the L{LogPublisher} associated with this L{LogBeginner}. 2. Optionally re-direct standard output and standard error streams to the logging system. 3. Re-play any messages that were previously logged to that publisher to the new observers, if C{discardBuffer} is not set. 4. Stop logging critical errors from the L{LogPublisher} as strings to the C{errorStream} associated with this L{LogBeginner}, and allow them to be logged normally. 5. Re-direct warnings from the L{warnings} module associated with this L{LogBeginner} to log messages. @note: Since a L{LogBeginner} is designed to encapsulate the transition between process-startup and log-system-configuration, this method is intended to be invoked I{once}. @param observers: The observers to register. @type observers: iterable of L{ILogObserver}s @param discardBuffer: Whether to discard the buffer and not re-play it to the added observers. (This argument is provided mainly for compatibility with legacy concerns.) @type discardBuffer: L{bool} @param redirectStandardIO: If true, redirect standard output and standard error to the observers. @type redirectStandardIO: L{bool} """ caller = currentframe(1) filename, lineno = caller.f_code.co_filename, caller.f_lineno for observer in observers: self._publisher.addObserver(observer) if self._temporaryObserver is not None: self._publisher.removeObserver(self._temporaryObserver) if not discardBuffer: self._initialBuffer.replayTo(self._publisher) self._temporaryObserver = None self._warningsModule.showwarning = self.showwarning else: previousFile, previousLine = self._previousBegin self._log.warn( MORE_THAN_ONCE_WARNING, fileNow=filename, lineNow=lineno, fileThen=previousFile, lineThen=previousLine, ) self._previousBegin = filename, lineno if redirectStandardIO: streams = [("stdout", LogLevel.info), ("stderr", LogLevel.error)] else: streams = [] for (stream, level) in streams: oldStream = getattr(self._stdio, stream) loggingFile = LoggingFile( logger=Logger(namespace=stream, observer=self._publisher), level=level, encoding=getattr(oldStream, "encoding", None), ) setattr(self._stdio, stream, loggingFile)
def beginLoggingTo(self, observers, discardBuffer=False, redirectStandardIO=True): """ Begin logging to the given set of observers. This will: 1. Add all the observers given in C{observers} to the L{LogPublisher} associated with this L{LogBeginner}. 2. Optionally re-direct standard output and standard error streams to the logging system. 3. Re-play any messages that were previously logged to that publisher to the new observers, if C{discardBuffer} is not set. 4. Stop logging critical errors from the L{LogPublisher} as strings to the C{errorStream} associated with this L{LogBeginner}, and allow them to be logged normally. 5. Re-direct warnings from the L{warnings} module associated with this L{LogBeginner} to log messages. @note: Since a L{LogBeginner} is designed to encapsulate the transition between process-startup and log-system-configuration, this method is intended to be invoked I{once}. @param observers: The observers to register. @type observers: iterable of L{ILogObserver}s @param discardBuffer: Whether to discard the buffer and not re-play it to the added observers. (This argument is provided mainly for compatibility with legacy concerns.) @type discardBuffer: L{bool} @param redirectStandardIO: If true, redirect standard output and standard error to the observers. @type redirectStandardIO: L{bool} """ caller = currentframe(1) filename, lineno = caller.f_code.co_filename, caller.f_lineno for observer in observers: self._publisher.addObserver(observer) if self._temporaryObserver is not None: self._publisher.removeObserver(self._temporaryObserver) if not discardBuffer: self._initialBuffer.replayTo(self._publisher) self._temporaryObserver = None self._warningsModule.showwarning = self.showwarning else: previousFile, previousLine = self._previousBegin self._log.warn( MORE_THAN_ONCE_WARNING, fileNow=filename, lineNow=lineno, fileThen=previousFile, lineThen=previousLine, ) self._previousBegin = filename, lineno if redirectStandardIO: streams = [("stdout", LogLevel.info), ("stderr", LogLevel.error)] else: streams = [] for (stream, level) in streams: oldStream = getattr(self._stdio, stream) loggingFile = LoggingFile( logger=Logger(namespace=stream, observer=self._publisher), level=level, encoding=getattr(oldStream, "encoding", None), ) setattr(self._stdio, stream, loggingFile)