Skip to content

Logging Configuration in od.config

The logging configuration is a dictionary object that specifies where and how log messages are sent.

The logging dictionary follows the Python logging module configuration format. Refer to the logging module documentation for the full specification.

The syslog and graylog protocols are also supported for remote log forwarding.

Limits

For HTTP responses only, each log line is limited by default to 2048 bytes.

In od.config, the max_log_body_size parameter is set to 2048 by default:

max_log_body_size: 2048

Adjust this value to increase or decrease the maximum length of a log line.

If a log line exceeds max_log_body_size, the string [truncated] replaces the end of the line:

2026-05-05 13:41:09 abcsrv23 132131221128896 od [INFO   ] __main__.trace_response:anonymous /core/getkeyinfo b'{"id": {"ephemeral_container": f...[truncated]'
2026-05-05 13:41:09 abcsrv23 132131237914304 orchestrator [DEBUG  ] oc.od.orchestrator.ODOrchestratorKubernetes.__init__:leela load_kube_config done
2026-05-05 13:41:09 abcsrv23 132131195950784 od [INFO   ] __main__.trace_response:anonymous /core/getkeyinfo b'{"id": null, "callbackurl": null...[truncated]'
2026-05-05 13:41:09 abcsrv23 132131237914304 orchestrator [DEBUG  ] oc.od.orchestrator.ODOrchestratorKubernetes.findDesktopByUser:leela 
2026-05-05 13:41:09 abcsrv23 132131237914304 orchestrator [DEBUG  ] oc.od.orchestrator.ODOrchestratorKubernetes.findPodByUser:leela 
2026-05-05 13:41:09 abcsrv23 132131237914304 orchestrator [DEBUG  ] oc.od.orchestrator.ODOrchestratorKubernetes.findDesktopByUser:leela Pod is found leela-be51a

Logging Configuration

The logging dictionary uses the Python logging module configuration format. Refer to the logging module documentation for the full specification.

The syslog and graylog protocols are also supported.

The default configuration for each handler is as follows:

handler Features
console log message using a logging.StreamHandler to the stream: ext://sys.stdout formated as standard
cherrypy_console log message using a logging.StreamHandler to the stream: ext://sys.stdout formatted as access
cherrypy_access log message using a logging.StreamHandler to the file stream logs/access.log formatted as access
cherrypy_trace log message using a logging.StreamHandler to the stream: logs/trace.log formatted as standard

Sub-modules used by od.py also emit log messages.

Sub module Default Values
docker.utils.config { 'level': 'INFO' },
urllib3.connectionpool { 'level': 'ERROR'},

The following is a sample logging configuration:

#              
# logging configuration 
# come from https://docs.python.org/3.8/library/logging.config.html
# need double %% to escape %
# 
# graylog https://github.com/severb/graypy
# use handler class name as
# graypy.GELFUDPHandler - UDP log forwarding
# graypy.GELFTCPHandler - TCP log forwarding
# graypy.GELFTLSHandler - TCP log forwarding with TLS support
# graypy.GELFHTTPHandler - HTTP log forwarding
# graypy.GELFRabbitHandler - RabbitMQ log forwarding

logging: {
    "version": 1,
    "disable_existing_loggers": False,
    'formatters': {
      'access': {
        'format': '%%(message)s - user: %%(userid)s',
        'datefmt': '%%Y-%%m-%%d %%H:%%M:%%S'
      },
      'standard': {
        'format': '%%(asctime)s %%(nodename)s %%(thread)d %%(module)s [%%(levelname)-7s] %%(name)s.%%(funcName)s:%%(userid)s %%(message)s',
        'datefmt': '%%Y-%%m-%%d %%H:%%M:%%S'
      },
      'syslog': {
        'format': '%%(asctime)s %%(nodename)s %%(thread)s %%(levelname)s %%(module)s %%(process)d %%(name)s.%%(funcName)s:%%(userid)s %%(message)s',
        'datefmt': '%%Y-%%m-%%d %%H:%%M:%%S'
      },
      'graylog': {
        'format': '%%(levelname)s %%(nodename)s %%(thread)s %%(module)s %%(process)d %%(name)s.%%(funcName)s:%%(userid)s %%(message)s'      
      }
    },
    'filters': {
      'odcontext': {
        '()': 'oc.logging.OdContextFilter'
      }
    },
    'handlers': {
      'stdout': {
        'class': 'logging.StreamHandler',
        'filters': [ 'odcontext' ],
        'level': 'DEBUG',
        'formatter': 'standard',
        'stream': 'ext://sys.stdout'
      },
      'stderr': {
        'class': 'logging.StreamHandler',
        'filters': [ 'odcontext' ],
        'level': 'ERROR',
        'formatter': 'standard',
        'stream': 'ext://sys.stderr'
      },
      'trace': {
        'class': 'logging.handlers.RotatingFileHandler',
        'level': 'DEBUG',
        'filters': [ 'odcontext' ],
        'formatter': 'standard',
        'filename': 'logs/trace.log',
        'maxBytes': 10485760,
        'backupCount': 20,
        'encoding': 'utf8',
        'mode': 'w'
      },
      'cherrypy_access': {
        'class': 'logging.handlers.RotatingFileHandler',
        'filters': [ 'odcontext' ],
        'formatter': 'access',
        'filename': 'logs/access.log',
        'maxBytes': 10485760,
        'backupCount': 20,
        'encoding': 'utf8'
      }
    },
    'loggers': {
      # dedicated python modules 
      'urllib3.connectionpool': {
        'level': 'ERROR',
      },
      'kubernetes': {
        'handlers': [ 'stderr', 'stdout',  'trace' ],
        'level': 'ERROR',
        'propagate': False
      },
      'cherrypy.access': {
        'handlers': [ 'cherrypy_access' ],
        'level': 'INFO',
        'propagate': False
      },
      'requests_oauthlib' : {
        'handlers': [ 'stderr', 'stdout',  'trace' ],
        'level': 'ERROR',
        'propagate': False
      },
      'cherrypy' : {
        'handlers': [ 'stderr', 'stdout',  'trace' ],
        'level': 'ERROR',
      }
    },
    'root': {
      # put the level to 'DEBUG', each handler fix the level value
      'level': 'DEBUG',
      'handlers': [ 'stderr', 'stdout',  'trace' ]
    }}