blob: 0d826878e6a1af527411cd5660d129afbe08ade3 [file] [log] [blame]
# ================================================================================
# Copyright (c) 2017-2018 AT&T Intellectual Property. All rights reserved.
# ================================================================================
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ============LICENSE_END=========================================================
#
# ECOMP is a trademark and service mark of AT&T Intellectual Property.
""":@CtxLogger.log_ctx: decorator for logging the cloudify ctx before and after operation"""
import json
import traceback
from functools import wraps
from cloudify import ctx
from cloudify.context import NODE_INSTANCE, RELATIONSHIP_INSTANCE
class CtxLogger(object):
"""static class for logging cloudify context ctx"""
@staticmethod
def _get_ctx_node_info(ctx_node):
if not ctx_node:
return {}
return {'id': ctx_node.id, 'name': ctx_node.name, 'type': ctx_node.type,
'type_hierarchy': ctx_node.type_hierarchy, 'properties': ctx_node.properties}
@staticmethod
def _get_ctx_instance_info(ctx_instance):
if not ctx_instance:
return {}
return {'id' : ctx_instance.id, 'runtime_properties' : ctx_instance.runtime_properties,
'relationships' : CtxLogger._get_ctx_instance_relationships_info(ctx_instance)}
@staticmethod
def _get_ctx_instance_relationships_info(ctx_instance):
if not ctx_instance or not ctx_instance.relationships:
return []
return [{'target': CtxLogger._get_ctx_source_target_info(r.target), \
'type':r.type, 'type_hierarchy':r.type_hierarchy} \
for r in ctx_instance.relationships]
@staticmethod
def _get_ctx_source_target_info(ctx_source_target):
if not ctx_source_target:
return {}
return {'node': CtxLogger._get_ctx_node_info(ctx_source_target.node),
'instance' : CtxLogger._get_ctx_instance_info(ctx_source_target.instance)}
@staticmethod
def get_ctx_info():
"""collect the context data from ctx"""
context = {
'type': ctx.type,
'blueprint.id': ctx.blueprint.id,
'deployment.id': ctx.deployment.id,
'execution_id': ctx.execution_id,
'workflow_id': ctx.workflow_id,
'task_id': ctx.task_id,
'task_name': ctx.task_name,
'task_queue': ctx.task_queue,
'task_target': ctx.task_target,
'operation': {
'name': ctx.operation.name,
'retry_number': ctx.operation.retry_number,
'max_retries': ctx.operation.max_retries
},
'plugin': {
'name': ctx.plugin.name,
'package_name': ctx.plugin.package_name,
'package_version': ctx.plugin.package_version,
'prefix': ctx.plugin.prefix,
'workdir': ctx.plugin.workdir
}
}
if ctx.type == NODE_INSTANCE:
context['node'] = CtxLogger._get_ctx_node_info(ctx.node)
context['instance'] = CtxLogger._get_ctx_instance_info(ctx.instance)
elif ctx.type == RELATIONSHIP_INSTANCE:
context['source'] = CtxLogger._get_ctx_source_target_info(ctx.source)
context['target'] = CtxLogger._get_ctx_source_target_info(ctx.target)
return context
@staticmethod
def log_ctx_info(func_name):
"""shortcut for logging of the ctx of the function"""
try:
if ctx.type == NODE_INSTANCE:
ctx.logger.info("{0} {1} context: {2}".format(\
func_name, ctx.instance.id, json.dumps(CtxLogger.get_ctx_info())))
elif ctx.type == RELATIONSHIP_INSTANCE:
ctx.logger.info("{0} context: {1}".format(\
func_name, json.dumps(CtxLogger.get_ctx_info())))
except Exception as ex:
ctx.logger.error("Failed to log the node context: {0}: {1}" \
.format(str(ex), traceback.format_exc()))
@staticmethod
def log_ctx(pre_log=True, after_log=False, exe_task=None):
"""Decorate each operation on the node to log the context - before and after.
Optionally save the current function name into runtime_properties[exe_task]
"""
def log_ctx_info_decorator(func, **arguments):
"""Decorate each operation on the node to log the context"""
if func is not None:
@wraps(func)
def wrapper(*args, **kwargs):
"""the actual logger before and after"""
try:
if ctx.type == NODE_INSTANCE and exe_task:
ctx.instance.runtime_properties[exe_task] = func.__name__
except Exception as ex:
ctx.logger.error("Failed to set exe_task {0}: {1}: {2}" \
.format(exe_task, str(ex), traceback.format_exc()))
if pre_log:
CtxLogger.log_ctx_info('before ' + func.__name__)
result = func(*args, **kwargs)
if after_log:
CtxLogger.log_ctx_info('after ' + func.__name__)
return result
return wrapper
return log_ctx_info_decorator