blob: 0d826878e6a1af527411cd5660d129afbe08ade3 [file] [log] [blame]
Alex Shatov8cdeeeb2017-09-26 17:03:11 -04001# ================================================================================
Lusheng Jicc307002018-02-12 11:04:54 -05002# Copyright (c) 2017-2018 AT&T Intellectual Property. All rights reserved.
Alex Shatov8cdeeeb2017-09-26 17:03:11 -04003# ================================================================================
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# ============LICENSE_END=========================================================
16#
17# ECOMP is a trademark and service mark of AT&T Intellectual Property.
18
Alex Shatov90f21052018-01-10 11:39:32 -050019""":@CtxLogger.log_ctx: decorator for logging the cloudify ctx before and after operation"""
20
Alex Shatov8cdeeeb2017-09-26 17:03:11 -040021import json
Alex Shatov90f21052018-01-10 11:39:32 -050022import traceback
Alex Shatov8cdeeeb2017-09-26 17:03:11 -040023from functools import wraps
24
25from cloudify import ctx
26from cloudify.context import NODE_INSTANCE, RELATIONSHIP_INSTANCE
27
28class CtxLogger(object):
29 """static class for logging cloudify context ctx"""
30 @staticmethod
31 def _get_ctx_node_info(ctx_node):
32 if not ctx_node:
33 return {}
34 return {'id': ctx_node.id, 'name': ctx_node.name, 'type': ctx_node.type,
35 'type_hierarchy': ctx_node.type_hierarchy, 'properties': ctx_node.properties}
36
37 @staticmethod
38 def _get_ctx_instance_info(ctx_instance):
39 if not ctx_instance:
40 return {}
41 return {'id' : ctx_instance.id, 'runtime_properties' : ctx_instance.runtime_properties,
42 'relationships' : CtxLogger._get_ctx_instance_relationships_info(ctx_instance)}
43
44 @staticmethod
45 def _get_ctx_instance_relationships_info(ctx_instance):
46 if not ctx_instance or not ctx_instance.relationships:
47 return []
48 return [{'target': CtxLogger._get_ctx_source_target_info(r.target), \
49 'type':r.type, 'type_hierarchy':r.type_hierarchy} \
50 for r in ctx_instance.relationships]
51
52 @staticmethod
53 def _get_ctx_source_target_info(ctx_source_target):
54 if not ctx_source_target:
55 return {}
56 return {'node': CtxLogger._get_ctx_node_info(ctx_source_target.node),
57 'instance' : CtxLogger._get_ctx_instance_info(ctx_source_target.instance)}
58
59 @staticmethod
60 def get_ctx_info():
61 """collect the context data from ctx"""
62 context = {
63 'type': ctx.type,
64 'blueprint.id': ctx.blueprint.id,
65 'deployment.id': ctx.deployment.id,
66 'execution_id': ctx.execution_id,
67 'workflow_id': ctx.workflow_id,
68 'task_id': ctx.task_id,
69 'task_name': ctx.task_name,
70 'task_queue': ctx.task_queue,
71 'task_target': ctx.task_target,
72 'operation': {
73 'name': ctx.operation.name,
74 'retry_number': ctx.operation.retry_number,
75 'max_retries': ctx.operation.max_retries
76 },
77 'plugin': {
78 'name': ctx.plugin.name,
79 'package_name': ctx.plugin.package_name,
80 'package_version': ctx.plugin.package_version,
81 'prefix': ctx.plugin.prefix,
82 'workdir': ctx.plugin.workdir
83 }
84 }
85 if ctx.type == NODE_INSTANCE:
86 context['node'] = CtxLogger._get_ctx_node_info(ctx.node)
87 context['instance'] = CtxLogger._get_ctx_instance_info(ctx.instance)
88 elif ctx.type == RELATIONSHIP_INSTANCE:
89 context['source'] = CtxLogger._get_ctx_source_target_info(ctx.source)
90 context['target'] = CtxLogger._get_ctx_source_target_info(ctx.target)
91
92 return context
93
94 @staticmethod
95 def log_ctx_info(func_name):
96 """shortcut for logging of the ctx of the function"""
97 try:
98 if ctx.type == NODE_INSTANCE:
99 ctx.logger.info("{0} {1} context: {2}".format(\
100 func_name, ctx.instance.id, json.dumps(CtxLogger.get_ctx_info())))
101 elif ctx.type == RELATIONSHIP_INSTANCE:
102 ctx.logger.info("{0} context: {1}".format(\
103 func_name, json.dumps(CtxLogger.get_ctx_info())))
104 except Exception as ex:
Alex Shatov90f21052018-01-10 11:39:32 -0500105 ctx.logger.error("Failed to log the node context: {0}: {1}" \
106 .format(str(ex), traceback.format_exc()))
Alex Shatov8cdeeeb2017-09-26 17:03:11 -0400107
108 @staticmethod
109 def log_ctx(pre_log=True, after_log=False, exe_task=None):
110 """Decorate each operation on the node to log the context - before and after.
111 Optionally save the current function name into runtime_properties[exe_task]
112 """
113 def log_ctx_info_decorator(func, **arguments):
114 """Decorate each operation on the node to log the context"""
115 if func is not None:
116 @wraps(func)
117 def wrapper(*args, **kwargs):
118 """the actual logger before and after"""
119 try:
120 if ctx.type == NODE_INSTANCE and exe_task:
121 ctx.instance.runtime_properties[exe_task] = func.__name__
122 except Exception as ex:
Alex Shatov90f21052018-01-10 11:39:32 -0500123 ctx.logger.error("Failed to set exe_task {0}: {1}: {2}" \
124 .format(exe_task, str(ex), traceback.format_exc()))
Alex Shatov8cdeeeb2017-09-26 17:03:11 -0400125 if pre_log:
126 CtxLogger.log_ctx_info('before ' + func.__name__)
127
128 result = func(*args, **kwargs)
129
130 if after_log:
131 CtxLogger.log_ctx_info('after ' + func.__name__)
132
133 return result
134 return wrapper
135 return log_ctx_info_decorator