Code Coverage

Cobertura Coverage Report > n2vc >

loggable.py

Trend

Classes100%
 
Lines26%
   
Conditionals100%
 

File Coverage summary

NameClassesLinesConditionals
loggable.py
100%
1/1
26%
21/82
100%
0/0

Coverage Breakdown by Class

NameLinesConditionals
loggable.py
26%
21/82
N/A

Source

n2vc/loggable.py
1 ##
2 # Copyright 2019 Telefonica Investigacion y Desarrollo, S.A.U.
3 # This file is part of OSM
4 # All Rights Reserved.
5 #
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
9 #
10 #    http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
15 # implied.
16 # See the License for the specific language governing permissions and
17 # limitations under the License.
18 #
19 # For those usages not covered by the Apache License, Version 2.0 please
20 # contact with: nfvlabs@tid.es
21 ##
22
23
24 1 import asyncio
25 1 import datetime
26 1 import inspect
27 1 import logging
28 1 import threading  # only for logging purposes (not for using threads)
29 1 import time
30
31
32 1 class Loggable:
33 1     def __init__(self, log, log_to_console: bool = False, prefix: str = ""):
34
35 1         self._last_log_time = None  # used for time increment in logging
36 1         self._log_to_console = log_to_console
37 1         self._prefix = prefix
38 1         if log is not None:
39 1             self.log = log
40         else:
41 1             self.log = logging.getLogger(__name__)
42
43 1     def debug(self, msg: str):
44 0         self._log_msg(log_level="DEBUG", msg=msg)
45
46 1     def info(self, msg: str):
47 0         self._log_msg(log_level="INFO", msg=msg)
48
49 1     def warning(self, msg: str):
50 0         self._log_msg(log_level="WARNING", msg=msg)
51
52 1     def error(self, msg: str):
53 0         self._log_msg(log_level="ERROR", msg=msg)
54
55 1     def critical(self, msg: str):
56 0         self._log_msg(log_level="CRITICAL", msg=msg)
57
58     ####################################################################################
59
60 1     def _log_msg(self, log_level: str, msg: str):
61         """Generic log method"""
62 0         msg = self._format_log(
63             log_level=log_level,
64             msg=msg,
65             obj=self,
66             level=3,
67             include_path=False,
68             include_thread=False,
69             include_coroutine=True,
70         )
71 0         if self._log_to_console:
72 0             print(msg)
73         else:
74 0             if self.log is not None:
75 0                 if log_level == "DEBUG":
76 0                     self.log.debug(msg)
77 0                 elif log_level == "INFO":
78 0                     self.log.info(msg)
79 0                 elif log_level == "WARNING":
80 0                     self.log.warning(msg)
81 0                 elif log_level == "ERROR":
82 0                     self.log.error(msg)
83 0                 elif log_level == "CRITICAL":
84 0                     self.log.critical(msg)
85
86 1     def _format_log(
87         self,
88         log_level: str,
89         msg: str = "",
90         obj: object = None,
91         level: int = None,
92         include_path: bool = False,
93         include_thread: bool = False,
94         include_coroutine: bool = True,
95     ) -> str:
96
97         # time increment from last log
98 0         now = time.perf_counter()
99 0         if self._last_log_time is None:
100 0             time_str = " (+0.000)"
101         else:
102 0             diff = round(now - self._last_log_time, 3)
103 0             time_str = " (+{})".format(diff)
104 0         self._last_log_time = now
105
106 0         if level is None:
107 0             level = 1
108
109         # stack info
110 0         fi = inspect.stack()[level]
111 0         filename = fi.filename
112 0         func = fi.function
113 0         lineno = fi.lineno
114         # filename without path
115 0         if not include_path:
116 0             i = filename.rfind("/")
117 0             if i > 0:
118 0                 filename = filename[i + 1:]
119
120         # datetime
121 0         dt = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
122 0         dt = dt + time_str
123         # dt = time_str       # logger already shows datetime
124
125         # current thread
126 0         if include_thread:
127 0             thread_name = "th:{}".format(threading.current_thread().getName())
128         else:
129 0             thread_name = ""
130
131         # current coroutine
132
133 0         coroutine_id = ""
134 0         if include_coroutine:
135 0             try:
136 0                 if asyncio.Task.current_task() is not None:
137
138 0                     def print_cor_name(c):
139 0                         import inspect
140
141 0                         try:
142 0                             for m in inspect.getmembers(c):
143 0                                 if m[0] == "__name__":
144 0                                     return m[1]
145 0                         except Exception:
146 0                             pass
147
148 0                     coro = asyncio.Task.current_task()._coro
149 0                     coroutine_id = "coro-{} {}()".format(
150                         hex(id(coro))[2:], print_cor_name(coro)
151                     )
152 0             except Exception:
153 0                 coroutine_id = ""
154
155         # classname
156 0         if obj is not None:
157 0             obj_type = obj.__class__.__name__  # type: str
158 0             log_msg = "{} {} {} {} {}::{}.{}():{}\n{}".format(
159                 self._prefix,
160                 dt,
161                 thread_name,
162                 coroutine_id,
163                 filename,
164                 obj_type,
165                 func,
166                 lineno,
167                 str(msg),
168             )
169         else:
170 0             log_msg = "{} {} {} {} {}::{}():{}\n{}".format(
171                 self._prefix,
172                 dt,
173                 thread_name,
174                 coroutine_id,
175                 filename,
176                 func,
177                 lineno,
178                 str(msg),
179             )
180
181 0         return log_msg