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