1 # -------------------------------------------------------------------------
2 # Copyright (c) 2015-2017 AT&T Intellectual Property
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
8 # http://www.apache.org/licenses/LICENSE-2.0
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.
16 # -------------------------------------------------------------------------
19 from logging import config
25 from osdf.logging import monkey
26 from osdf.utils.programming_utils import MetaSingleton
28 BASE_DIR = os.path.dirname(__file__)
29 LOGGING_FILE = os.path.join(BASE_DIR, '..', '..', 'config', 'log.yml')
32 def format_exception(err, prefix=None):
33 """Format operation for use with ecomp logging
35 :param err: exception object
36 :param prefix: prefix string message
37 :return: formatted exception (via repr(traceback.format_tb(err.__traceback__))
39 exception_lines = traceback.format_exception(err.__class__, err, err.__traceback__)
40 exception_desc = "".join(exception_lines)
41 return exception_desc if not prefix else prefix + ": " + exception_desc
44 def create_log_dirs():
45 with open(LOGGING_FILE, 'r') as fid:
46 yaml_config = yaml.full_load(fid)
47 for key in yaml_config['handlers']:
48 a = yaml_config['handlers'][key]
50 os.makedirs(os.path.dirname(a['filename']), exist_ok=True)
53 class OOFOSDFLogMessageHelper(metaclass=MetaSingleton):
54 """Provides loggers as a singleton (otherwise, we end up with duplicate messages).
56 Provides error_log, metric_log, audit_log, and debug_log (in that order)
58 Additionally can provide specific log handlers too
61 default_levels = ["error", "metrics", "audit", "debug"]
63 def get_handlers(self, levels=None):
64 """Return ONAP-compliant log handlers for different levels. Each "level" ends up in a different log file
66 with a prefix of that level.
68 For example: error_log, metrics_log, audit_log, debug_log in that order
70 :param levels: None or list of levels subset of self.default_levels (["error", "metrics", "audit", "debug"])
72 :return: list of log_handlers in the order of levels requested.
73 if levels is None: we return handlers for self.default_levels
74 if levels is ["error", "audit"], we return log handlers for that.
78 config.yamlConfig(filepath=LOGGING_FILE, watchDog=False)
79 wanted_levels = self.default_levels if levels is None else levels
80 return [logging.getLogger(x) for x in wanted_levels]
83 class OOFOSDFLogMessageFormatter(object):
86 def accepted_valid_request(req_id, request):
87 """valid request message formatter
90 return "Accepted valid request for ID: {} for endpoint: {}".format(
94 def invalid_request(req_id, err):
95 """invalid request message formatter
98 return "Invalid request for request ID: {}; cause: {}".format(
99 req_id, format_exception(err))
102 def invalid_response(req_id, err):
103 """invalid response message formatter
106 return "Invalid response for request ID: {}; cause: {}".format(
107 req_id, format_exception(err))
110 def malformed_request(request, err):
111 """Malformed request message formatter
114 return "Malformed request for URL {}, from {}; cause: {}".format(
115 request.url, request.remote_address, format_exception(err))
118 def malformed_response(response, client, err):
119 """Malformed response message formatter
122 return "Malformed response {} for client {}; cause: {}".format(
123 response, client, format_exception(err))
126 def need_policies(req_id):
127 """Policies needed message formatter
130 return "Policies required but found no policies for request ID: {}".format(req_id)
133 def policy_service_error(url, req_id, err):
134 """policy service error message formatter
137 return "Unable to call policy for {} for request ID: {}; cause: {}".format(
138 url, req_id, format_exception(err))
141 def requesting_url(url, req_id):
142 """Message formatter for requesting url
145 return "Making a call to URL {} for request ID: {}".format(url, req_id)
148 def requesting(service_name, req_id):
149 """Message formatter for requesting a service
152 return "Making a call to service {} for request ID: {}".format(service_name, req_id)
155 def error_requesting(service_name, req_id, err):
156 """Message formatter on error requesting a service
159 return "Error while requesting service {} for request ID: {}; cause: {}".format(
160 service_name, req_id, format_exception(err))
163 def calling_back(req_id, callback_url):
164 """Message formatter when a callback url is invoked
167 return "Posting result to callback URL for request ID: {}; callback URL={}".format(
168 req_id, callback_url)
171 def calling_back_with_body(req_id, callback_url, body):
172 """Message formatter when a callback url with body is invoked
175 return "Posting result to callback URL for request ID: {}; callback URL={} body={}".format(
176 req_id, callback_url, body)
179 def error_calling_back(req_id, callback_url, err):
180 """Message formatter on an error while posting result to callback url
183 return "Error while posting result to callback URL {} for request ID: {}; cause: {}".format(
184 req_id, callback_url, format_exception(err))
187 def received_request(url, remote_addr, json_body):
188 """Message when a call is received
191 return "Received a call to {} from {} {}".format(url, remote_addr, json_body)
194 def new_worker_thread(req_id, extra_msg=""):
195 """Message on invoking a new worker thread
198 res = "Initiating new worker thread for request ID: {}".format(req_id)
199 return res + extra_msg
202 def inside_worker_thread(req_id, extra_msg=""):
203 """Message when inside a worker thread
206 res = "Inside worker thread for request ID: {}".format(req_id)
207 return res + extra_msg
210 def processing(req_id, desc):
211 """Processing a request
214 return "Processing request ID: {} -- {}".format(req_id, desc)
217 def processed(req_id, desc):
218 """Processed the request
221 return "Processed request ID: {} -- {}".format(req_id, desc)
224 def error_while_processing(req_id, desc, err):
225 """Error while processing the request
228 return "Error while processing request ID: {} -- {}; cause: {}".format(
229 req_id, desc, format_exception(err))
232 def creating_local_env(req_id):
233 """Creating a local environment
236 return "Creating local environment request ID: {}".format(
240 def error_local_env(req_id, desc, err):
241 """Error creating a local env
244 return "Error while creating local environment for request ID: {} -- {}; cause: {}".format(
245 req_id, desc, err.__traceback__)
248 def inside_new_thread(req_id, extra_msg=""):
249 """Inside a new thread
252 res = "Spinning up a new thread for request ID: {}".format(req_id)
253 return res + " " + extra_msg
256 def error_response_posting(req_id, desc, err):
257 """Error while posting a response
260 return "Error while posting a response for a request ID: {} -- {}; cause: {}".format(
261 req_id, desc, err.__traceback__)
264 def received_http_response(resp):
265 """Received a http response
268 return "Received response [code: {}, headers: {}, data: {}]".format(
269 resp.status_code, resp.headers, resp.__dict__)
272 def sending_response(req_id, desc):
273 """sending a response
276 return "Response is sent for request ID: {} -- {}".format(
280 def listening_response(req_id, desc):
281 """Resposne is sent for a request ID
284 return "Response is sent for request ID: {} -- {}".format(
288 def items_received(item_num, item_type, desc="Received"):
292 return "{} {} {}".format(desc, item_num, item_type)
295 def items_sent(item_num, item_type, desc="Published"):
299 return "{} {} {}".format(desc, item_num, item_type)
302 MH = OOFOSDFLogMessageFormatter
304 error_log, metrics_log, audit_log, debug_log = OOFOSDFLogMessageHelper().get_handlers()
307 def warn_audit_error(msg):
308 """Log the message to error_log.warn and audit_log.warn
311 log_message_multi(msg, audit_log.warn, error_log.warn)
314 def log_message_multi(msg, *logger_methods):
315 """Log the msg to multiple loggers
317 :param msg: message to log
318 :param logger_methods: e.g. error_log.warn, audit_log.warn, etc.
320 for log_method in logger_methods: