onaplogging: Docstrings, refactor, type hinting
[logging-analytics.git] / pylog / onaplogging / markerLogAdaptor.py
1 # Copyright 2018 ke liang <lokyse@163.com>.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #         http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 from logging import LoggerAdapter
16 from threading import RLock
17 from functools import wraps
18 from deprecated import deprecated
19 from typing import Dict, Callable
20
21 from onaplogging.utils.system import is_above_python_3_2
22
23 from .marker import Marker, MARKER_TAG
24 from .mdcContext import _getmdcs
25
26 lock = RLock()
27
28
29 def add_marker(func):
30     # type: ( Callable[[Marker, str], None] ) -> Callable[[Marker, str], None]
31     """Marker decorator.
32
33     Requests a blocking acquisition of the thread. Sets the marker
34     as the logger's marker and delegates a call to the underlying
35     logger with contextual information. Next it removes the marker
36     and releases the thread.
37
38     Args:
39         func        : a method supplied with a logging marker.
40     Raises:
41         TypeError   : the marker type is not `Marker`.
42         Exception   : `extra` doesn't exist or MARKER_TAG is in `extra`.
43
44     Returns:
45         method: decorated method.
46     """
47     @wraps(func)
48     def wrapper(self, marker, msg, *args, **kwargs):
49         # type: (Marker, str) -> Callable[[Marker, str], None]
50
51         lock.acquire()
52
53         if not isinstance(marker, Marker):
54             raise TypeError("Passed a marker of type %s. \
55                              Should have the type %s."
56                             % type(marker), "Marker")
57
58         if  self.extra and \
59             MARKER_TAG in self.extra:
60             raise Exception("Can't add 'marker' in extra - either extra \
61                              exists or MARKER_TAG is alredy in extra")
62
63         setattr(self.logger, MARKER_TAG, marker)
64
65         func(self, marker, msg, *args, **kwargs)
66
67         if hasattr(self.logger, MARKER_TAG):
68             delattr(self.logger, MARKER_TAG)
69
70         lock.release()
71
72     return wrapper
73
74
75 @deprecated(reason="@addMarker is deprecated. Use @add_marker instead.")
76 def addMarker(func):
77     """Decorator. See new decorator add_marker(func)."""
78     add_marker(func)
79
80
81 class MarkerLogAdaptor(LoggerAdapter):
82     """Contextual loggin adapter.
83
84     Specifies contextual information in logging output. Takes a logger and a
85     dictionary-like object `extra` for providing contextual information.
86
87     An example of the extra contextual information:
88     extra = {'app_name':'Marker Logging'}
89
90     Extends:
91         logging.LoggerAdapter
92     """
93
94     def process(self, msg, kwargs):
95         # type: (str, Dict)
96         """Logging call processor.
97
98         Takes a logging message and keyword arguments to provide cotextual
99         information.
100
101         Args:
102             msg     : Logging information.
103             kwargs  : Contextual information.
104         Returns:
105             str     : Logging message.
106             dict    : modified (or not) contextual information.
107         """
108         if is_above_python_3_2():
109             kwargs['extra'] = _getmdcs(self.extra)
110         else:
111             kwargs['extra'] = self.extra
112         return msg, kwargs
113
114     @add_marker
115     def info_marker(self, marker, msg, *args, **kwargs):
116         # type: (Marker, str) -> None
117         """Provide the logger with an informational call."""
118         self.info(msg, *args, **kwargs)
119
120     @add_marker
121     def debug_marker(self, marker, msg, *args, **kwargs):
122         # type: (Marker, str) -> None
123         """Provide the logger with a debug call."""
124         self.debug(msg, *args, **kwargs)
125
126     @add_marker
127     def warning_marker(self, marker, msg, *args, **kwargs):
128         # type: (Marker, str) -> None
129         """Provide the logger with a warning call."""
130         self.warning(msg, *args, **kwargs)
131
132     @add_marker
133     def error_marker(self, marker, msg, *args, **kwargs):
134         # type: (Marker, str) -> None
135         """Provide the logger with an error call."""
136         self.error(msg, *args, **kwargs)
137
138     @add_marker
139     def exception_marker(self, marker, msg, *args, **kwargs):
140         # type: (Marker, str) -> None
141         """Provide the logger with an exceptional call."""
142         self.exception(msg, *args, **kwargs)
143
144     @add_marker
145     def critical_marker(self, marker, msg, *args, **kwargs):
146         # type: (Marker, str) -> None
147         """Provide the logger with a critical call."""
148         self.critical(msg, *args, **kwargs)
149
150     @add_marker
151     def log_marker(self, marker, level, msg, *args, **kwargs):
152         # type: (Marker, str) -> None
153         """Provide the logger with a log call."""
154         self.log(marker, level, msg, *args, **kwargs)
155
156     @deprecated(reason="infoMarker(...) is replaced with info_marker(...).")
157     def infoMarker(self, marker, msg, *args, **kwargs):
158         self.info_marker(marker, msg, *args, **kwargs)
159
160     @deprecated(reason="debugMarker(...) is replaced with debug_marker(...).")
161     def debugMarker(self, marker, msg, *args, **kwargs):
162         self.debug_marker(marker, msg, *args, **kwargs)
163
164     @deprecated(reason="warningMarker(...) replaced, use warning_marker(...).")
165     def warningMarker(self, marker, msg, *args, **kwargs):
166         self.warning_marker(marker, msg, *args, **kwargs)
167
168     @deprecated(reason="errorMarker(...) is replaced with error_marker(...).")
169     def errorMarker(self, marker, msg, *args, **kwargs):
170         self.error_marker(marker, msg, *args, **kwargs)
171
172     @deprecated(reason="exceptionMarker(...) replaced,"
173         " use exception_marker(...).")
174     def exceptionMarker(self, marker, msg, *args, **kwargs):
175         self.exception_marker(marker, msg, *args, **kwargs)
176
177     @deprecated(reason="criticalMarker(...) is replaced, "
178         "use critical_marker(...).")
179     def criticalMarker(self, marker, msg, *args, **kwargs):
180         self.critical_marker(marker, msg, *args, **kwargs)
181
182     @deprecated(reason="logMarker(...) is replaced with info_marker(...).")
183     def logMarker(self, marker, level, msg, *args, **kwargs):
184         self.log_marker(marker, level, msg, *args, **kwargs)