Skip to content

Commit

Permalink
[Python] Remove obsolete logging callbacks (#33718)
Browse files Browse the repository at this point in the history
Since #5024 there is a new logging callback working. The old code has
partially been removed in #4690, but never completely. Drop the old
logging code for good.
  • Loading branch information
agners authored and pull[bot] committed Jun 19, 2024
1 parent 6ad2c52 commit ae5ef65
Show file tree
Hide file tree
Showing 2 changed files with 2 additions and 158 deletions.
12 changes: 0 additions & 12 deletions src/controller/python/ChipDeviceController-ScriptBinding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,6 @@ PyChipError pychip_DeviceCommissioner_CloseBleConnection(chip::Controller::Devic

const char * pychip_Stack_ErrorToString(ChipError::StorageType err);
const char * pychip_Stack_StatusReportToString(uint32_t profileId, uint16_t statusCode);
void pychip_Stack_SetLogFunct(LogMessageFunct logFunct);

PyChipError pychip_GetConnectedDeviceByNodeId(chip::Controller::DeviceCommissioner * devCtrl, chip::NodeId nodeId,
chip::Controller::Python::PyObject * context, DeviceAvailableFunc callback);
Expand Down Expand Up @@ -863,17 +862,6 @@ uint64_t pychip_GetCommandSenderHandle(chip::DeviceProxy * device)
return 0;
}

void pychip_Stack_SetLogFunct(LogMessageFunct logFunct)
{
// TODO: determine if log redirection is supposed to be functioning in CHIP
//
// Background: original log baseline supported 'redirect logs to this
// function' however CHIP does not currently provide this.
//
// Ideally log redirection should work so that python code can do things
// like using the log module.
}

PyChipError pychip_DeviceController_PostTaskOnChipThread(ChipThreadTaskRunnerFunct callback, void * pythonContext)
{
if (callback == nullptr || pythonContext == nullptr)
Expand Down
148 changes: 2 additions & 146 deletions src/controller/python/chip/ChipStack.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,11 @@

import asyncio
import builtins
import logging
import os
import sys
import time
from ctypes import CFUNCTYPE, Structure, c_bool, c_char_p, c_int64, c_uint8, c_uint16, c_uint32, c_void_p, py_object, pythonapi
from ctypes import CFUNCTYPE, Structure, c_bool, c_char_p, c_uint16, c_uint32, c_void_p, py_object, pythonapi
from threading import Condition, Event, Lock

import chip.native
from chip.logging import LOG_CATEGORY_AUTOMATION, LOG_CATEGORY_DETAIL, LOG_CATEGORY_ERROR, LOG_CATEGORY_PROGRESS
from chip.native import PyChipError

from .ChipUtility import ChipUtility
Expand Down Expand Up @@ -76,51 +72,6 @@ class DeviceStatusStruct(Structure):
]


class LogCategory(object):
"""Debug logging categories used by chip."""

@staticmethod
def categoryToLogLevel(cat):
if cat == LOG_CATEGORY_ERROR:
return logging.ERROR
elif cat == LOG_CATEGORY_PROGRESS:
return logging.INFO
elif cat in (LOG_CATEGORY_DETAIL, LOG_CATEGORY_AUTOMATION):
return logging.DEBUG
else:
return logging.NOTSET


class ChipLogFormatter(logging.Formatter):
"""A custom logging.Formatter for logging chip library messages."""

def __init__(
self,
datefmt=None,
logModulePrefix=False,
logLevel=False,
logTimestamp=False,
logMSecs=True,
):
fmt = "%(message)s"
if logModulePrefix:
fmt = "CHIP:%(chip-module)s: " + fmt
if logLevel:
fmt = "%(levelname)s:" + fmt
if datefmt is not None or logTimestamp:
fmt = "%(asctime)s " + fmt
super(ChipLogFormatter, self).__init__(fmt=fmt, datefmt=datefmt)
self.logMSecs = logMSecs

def formatTime(self, record, datefmt=None):
if datefmt is None:
timestampStr = time.strftime("%Y-%m-%d %H:%M:%S%z")
if self.logMSecs:
timestampUS = record.__dict__.get("timestamp-usec", 0)
timestampStr = "%s.%03ld" % (timestampStr, timestampUS / 1000)
return timestampStr


class AsyncCallableHandle:
def __init__(self, callback):
self._callback = callback
Expand Down Expand Up @@ -185,15 +136,12 @@ def __call__(self):
pythonapi.Py_DecRef(py_object(self))


_LogMessageFunct = CFUNCTYPE(
None, c_int64, c_int64, c_char_p, c_uint8, c_char_p)
_ChipThreadTaskRunnerFunct = CFUNCTYPE(None, py_object)


@_singleton
class ChipStack(object):
def __init__(self, persistentStoragePath: str, installDefaultLogHandler=True,
bluetoothAdapter=None, enableServerInteractions=True):
def __init__(self, persistentStoragePath: str, enableServerInteractions=True):
builtins.enableDebugMode = False

# TODO: Probably no longer necessary, see https://github.com/project-chip/connectedhomeip/issues/33321.
Expand All @@ -206,8 +154,6 @@ def __init__(self, persistentStoragePath: str, installDefaultLogHandler=True,
self.callbackRes = None
self.commissioningEventRes = None
self.openCommissioningWindowPincode = {}
self._activeLogFunct = None
self.addModulePrefixToLogMessage = True
self._enableServerInteractions = enableServerInteractions

#
Expand All @@ -216,50 +162,6 @@ def __init__(self, persistentStoragePath: str, installDefaultLogHandler=True,
#
self._loadLib()

# Arrange to log output from the chip library to a python logger object with the
# name 'chip.ChipStack'. If desired, applications can override this behavior by
# setting self.logger to a different python logger object, or by calling setLogFunct()
# with their own logging function.
self.logger = logging.getLogger(__name__)
self.setLogFunct(self.defaultLogFunct)

# Determine if there are already handlers installed for the logger. Python 3.5+
# has a method for this; on older versions the check has to be done manually.
if hasattr(self.logger, "hasHandlers"):
hasHandlers = self.logger.hasHandlers()
else:
hasHandlers = False
logger = self.logger
while logger is not None:
if len(logger.handlers) > 0:
hasHandlers = True
break
if not logger.propagate:
break
logger = logger.parent

# If a logging handler has not already been initialized for 'chip.ChipStack',
# or any one of its parent loggers, automatically configure a handler to log to
# stdout. This maintains compatibility with a number of applications which expect
# chip log output to go to stdout by default.
#
# This behavior can be overridden in a variety of ways:
# - Initialize a different log handler before ChipStack is initialized.
# - Pass installDefaultLogHandler=False when initializing ChipStack.
# - Replace the StreamHandler on self.logger with a different handler object.
# - Set a different Formatter object on the existing StreamHandler object.
# - Reconfigure the existing ChipLogFormatter object.
# - Configure chip to call an application-specific logging function by
# calling self.setLogFunct().
# - Call self.setLogFunct(None), which will configure the chip library
# to log directly to stdout, bypassing python altogether.
#
if installDefaultLogHandler and not hasHandlers:
logHandler = logging.StreamHandler(stream=sys.stdout)
logHandler.setFormatter(ChipLogFormatter())
self.logger.addHandler(logHandler)
self.logger.setLevel(logging.DEBUG)

@_ChipThreadTaskRunnerFunct
def HandleChipThreadRun(callback):
callback()
Expand Down Expand Up @@ -292,49 +194,6 @@ def GetStorageManager(self):
def enableServerInteractions(self):
return self._enableServerInteractions

@property
def defaultLogFunct(self):
"""Returns a python callable which, when called, logs a message to the python logger object
currently associated with the ChipStack object.
The returned function is suitable for passing to the setLogFunct() method."""

def logFunct(timestamp, timestampUSec, moduleName, logCat, message):
moduleName = ChipUtility.CStringToString(moduleName)
message = ChipUtility.CStringToString(message)
if self.addModulePrefixToLogMessage:
message = "CHIP:%s: %s" % (moduleName, message)
logLevel = LogCategory.categoryToLogLevel(logCat)
msgAttrs = {
"chip-module": moduleName,
"timestamp": timestamp,
"timestamp-usec": timestampUSec,
}
self.logger.log(logLevel, message, extra=msgAttrs)

return logFunct

def setLogFunct(self, logFunct):
"""Set the function used by the chip library to log messages.
The supplied object must be a python callable that accepts the following
arguments:
timestamp (integer)
timestampUS (integer)
module name (encoded UTF-8 string)
log category (integer)
message (encoded UTF-8 string)
Specifying None configures the chip library to log directly to stdout."""
if logFunct is None:
logFunct = 0
if not isinstance(logFunct, _LogMessageFunct):
logFunct = _LogMessageFunct(logFunct)
# TODO: Lock probably no longer necessary, see https://github.com/project-chip/connectedhomeip/issues/33321.
with self.networkLock:
# NOTE: ChipStack must hold a reference to the CFUNCTYPE object while it is
# set. Otherwise it may get garbage collected, and logging calls from the
# chip library will fail.
self._activeLogFunct = logFunct
self._ChipStackLib.pychip_Stack_SetLogFunct(logFunct)

def Shutdown(self):
#
# Terminate Matter thread and shutdown the stack.
Expand Down Expand Up @@ -484,9 +343,6 @@ def _loadLib(self):
self._ChipStackLib.pychip_Stack_StatusReportToString.restype = c_char_p
self._ChipStackLib.pychip_Stack_ErrorToString.argtypes = [c_uint32]
self._ChipStackLib.pychip_Stack_ErrorToString.restype = c_char_p
self._ChipStackLib.pychip_Stack_SetLogFunct.argtypes = [
_LogMessageFunct]
self._ChipStackLib.pychip_Stack_SetLogFunct.restype = PyChipError

self._ChipStackLib.pychip_DeviceController_PostTaskOnChipThread.argtypes = [
_ChipThreadTaskRunnerFunct, py_object]
Expand Down

0 comments on commit ae5ef65

Please sign in to comment.