blob: 828c439b415f0fc2197ffd9f80007d6e06b2a9c4 [file] [log] [blame]
Zsolt Haraszti86be6f12016-09-27 09:56:49 -07001#
Zsolt Haraszti3eb27a52017-01-03 21:56:48 -08002# Copyright 2017 the original author or authors.
Zsolt Haraszti86be6f12016-09-27 09:56:49 -07003#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16
17"""Setting up proper logging for Voltha"""
18
19import logging
20import logging.config
21from collections import OrderedDict
22
23import structlog
24from structlog.stdlib import BoundLogger, INFO
25
26try:
27 from thread import get_ident as _get_ident
28except ImportError:
29 from dummy_thread import get_ident as _get_ident
30
31
khenaidoo50b286d2018-03-02 17:44:30 -050032class StructuredLogRenderer(object):
Zsolt Haraszti86be6f12016-09-27 09:56:49 -070033 def __call__(self, logger, name, event_dict):
34 # in order to keep structured log data in event_dict to be forwarded as
khenaidoo50b286d2018-03-02 17:44:30 -050035 # is, we need to pass it into the logger framework as the first
36 # positional argument.
37 args = (event_dict,)
Zsolt Haraszti86be6f12016-09-27 09:56:49 -070038 kwargs = {}
39 return args, kwargs
40
41
42class PlainRenderedOrderedDict(OrderedDict):
43 """Our special version of OrderedDict that renders into string as a dict,
44 to make the log stream output cleaner.
45 """
46 def __repr__(self, _repr_running={}):
47 'od.__repr__() <==> repr(od)'
48 call_key = id(self), _get_ident()
49 if call_key in _repr_running:
50 return '...'
51 _repr_running[call_key] = 1
52 try:
53 if not self:
54 return '{}'
55 return '{%s}' % ", ".join("%s: %s" % (k, v)
56 for k, v in self.items())
57 finally:
58 del _repr_running[call_key]
59
60
khenaidoo50b286d2018-03-02 17:44:30 -050061def setup_logging(log_config, instance_id, verbosity_adjust=0):
Zsolt Haraszti86be6f12016-09-27 09:56:49 -070062 """
63 Set up logging such that:
64 - The primary logging entry method is structlog
65 (see http://structlog.readthedocs.io/en/stable/index.html)
66 - By default, the logging backend is Python standard lib logger
Zsolt Haraszti86be6f12016-09-27 09:56:49 -070067 """
68
69 def add_exc_info_flag_for_exception(_, name, event_dict):
70 if name == 'exception':
71 event_dict['exc_info'] = True
72 return event_dict
73
74 def add_instance_id(_, __, event_dict):
75 event_dict['instance_id'] = instance_id
76 return event_dict
77
Zsolt Haraszti86be6f12016-09-27 09:56:49 -070078 # Configure standard logging
79 logging.config.dictConfig(log_config)
80 logging.root.level -= 10 * verbosity_adjust
81
Matteo Scandolo3d7abcc2018-09-13 17:02:00 -070082 # Add TRACE log level (lower than DEBUG:10)
83 TRACE_LOGLVL = 5
84 logging.addLevelName(TRACE_LOGLVL, "TRACE")
85 def trace_loglevel(self, message, *args, **kws):
86 if self.isEnabledFor(TRACE_LOGLVL):
87 self._log(TRACE_LOGLVL, message, args, **kws)
88 logging.Logger.trace = trace_loglevel
89
Zsolt Haraszti86be6f12016-09-27 09:56:49 -070090 processors = [
91 add_exc_info_flag_for_exception,
92 structlog.processors.StackInfoRenderer(),
93 structlog.processors.format_exc_info,
94 add_instance_id,
khenaidoo50b286d2018-03-02 17:44:30 -050095 StructuredLogRenderer(),
Zsolt Haraszti86be6f12016-09-27 09:56:49 -070096 ]
97 structlog.configure(logger_factory=structlog.stdlib.LoggerFactory(),
98 context_class=PlainRenderedOrderedDict,
99 wrapper_class=BoundLogger,
100 processors=processors)
101
102 # Mark first line of log
103 log = structlog.get_logger()
104 log.info("first-line")
105 return log
khenaidoocbe30832017-08-25 10:43:27 -0400106
khenaidoocbe30832017-08-25 10:43:27 -0400107def update_logging(instance_id, vcore_id):
108 """
109 Add the vcore id to the structured logger
110 :param vcore_id: The assigned vcore id
111 :return: structure logger
112 """
113 def add_exc_info_flag_for_exception(_, name, event_dict):
114 if name == 'exception':
115 event_dict['exc_info'] = True
116 return event_dict
117
118 def add_instance_id(_, __, event_dict):
119 event_dict['instance_id'] = instance_id
120 return event_dict
121
122 def add_vcore_id(_, __, event_dict):
123 event_dict['vcore_id'] = vcore_id
124 return event_dict
125
126 processors = [
127 add_exc_info_flag_for_exception,
128 structlog.processors.StackInfoRenderer(),
129 structlog.processors.format_exc_info,
130 add_instance_id,
131 add_vcore_id,
khenaidoo50b286d2018-03-02 17:44:30 -0500132 StructuredLogRenderer(),
khenaidoocbe30832017-08-25 10:43:27 -0400133 ]
134 structlog.configure(processors=processors)
135
136 # Mark first line of log
137 log = structlog.get_logger()
138 log.info("updated-logger")
139 return log