vFW and vDNS support added to azure-plugin
[multicloud/azure.git] / azure / aria / aria-extension-cloudify / src / aria / aria / logger.py
1 # Licensed to the Apache Software Foundation (ASF) under one or more
2 # contributor license agreements.  See the NOTICE file distributed with
3 # this work for additional information regarding copyright ownership.
4 # The ASF licenses this file to You under the Apache License, Version 2.0
5 # (the "License"); you may not use this file except in compliance with
6 # the License.  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
16 """
17 Mix-ins and functions for logging, supporting multiple backends (such as SQL) and consistent
18 formatting.
19 """
20
21 import logging
22 from logging import handlers as logging_handlers
23 # NullHandler doesn't exist in < 27. this workaround is from
24 # http://docs.python.org/release/2.6/library/logging.html#configuring-logging-for-a-library
25 try:
26     from logging import NullHandler                                                                 # pylint: disable=unused-import
27 except ImportError:
28     class NullHandler(logging.Handler):
29         def emit(self, record):
30             pass
31 from datetime import datetime
32
33
34 TASK_LOGGER_NAME = 'aria.executions.task'
35
36
37 _base_logger = logging.getLogger('aria')
38
39
40 class LoggerMixin(object):
41     """
42     Provides logging functionality to a class.
43
44     :ivar logger_name: logger name; default to the class name
45     :ivar logger_level: logger level; defaults to ``logging.DEBUG``
46     :ivar base_logger: child loggers are created from this; defaults to the root logger
47     """
48     logger_name = None
49     logger_level = logging.DEBUG
50
51     def __init__(self, *args, **kwargs):
52         self.logger_name = self.logger_name or self.__class__.__name__
53         self.logger = logging.getLogger('{0}.{1}'.format(_base_logger.name, self.logger_name))
54         # Set the logger handler of any object derived from LoggerMixing to NullHandler.
55         # This is since the absence of a handler shows up while using the CLI in the form of:
56         # `No handlers could be found for logger "..."`.
57         self.logger.addHandler(NullHandler())
58         self.logger.setLevel(self.logger_level)
59         super(LoggerMixin, self).__init__(*args, **kwargs)
60
61     @classmethod
62     def with_logger(
63             cls,
64             logger_name=None,
65             logger_level=logging.DEBUG,
66             base_logger=logging.getLogger(),
67             **kwargs):
68         """
69         Set the logger used by the consuming class.
70         """
71         cls.logger_name = logger_name
72         cls.logger_level = logger_level
73         cls.base_logger = base_logger
74         return cls(**kwargs)
75
76     def __getstate__(self):
77         obj_dict = vars(self).copy()
78         del obj_dict['logger']
79         return obj_dict
80
81     def __setstate__(self, obj_dict):
82         vars(self).update(
83             logger=logging.getLogger('{0}.{1}'.format(_base_logger.name, obj_dict['logger_name'])),
84             **obj_dict)
85
86
87 def create_logger(logger=_base_logger, handlers=(), **configs):
88     """
89     :param logger: logger name; defaults to ARIA logger
90     :type logger: logging.Logger
91     :param handlers: logger handlers
92     :type handlers: []
93     :param configs: logger configurations
94     :type configs: []
95     :return: logger
96     """
97     logger.handlers = []
98     for handler in handlers:
99         logger.addHandler(handler)
100
101     logger.setLevel(configs.get('level', logging.DEBUG))
102     logger.debug('Logger {0} configured'.format(logger.name))
103     return logger
104
105
106 def create_console_log_handler(level=logging.DEBUG, formatter=None):
107     """
108     :param level:
109     :param formatter:
110     """
111     console = logging.StreamHandler()
112     console.setLevel(level)
113     console.formatter = formatter or _DefaultConsoleFormat()
114     return console
115
116
117 def create_sqla_log_handler(model, log_cls, execution_id, level=logging.DEBUG):
118
119     # This is needed since the engine and session are entirely new we need to reflect the db
120     # schema of the logging model into the engine and session.
121     return _SQLAlchemyHandler(model=model, log_cls=log_cls, execution_id=execution_id, level=level)
122
123
124 class _DefaultConsoleFormat(logging.Formatter):
125     """
126     Info level log format: ``%(message)s``.
127
128     Every other log level is formatted: ``%(levelname)s: %(message)s``.
129     """
130     def format(self, record):
131         try:
132             if hasattr(record, 'prefix'):
133                 self._fmt = '<%(asctime)s: [%(levelname)s] @%(prefix)s> %(message)s'
134             else:
135                 self._fmt = '<%(asctime)s: [%(levelname)s]> %(message)s'
136
137         except AttributeError:
138             return record.message
139         return logging.Formatter.format(self, record)
140
141
142 def create_file_log_handler(
143         file_path,
144         level=logging.DEBUG,
145         max_bytes=5 * 1000 * 1024,
146         backup_count=10,
147         formatter=None):
148     """
149     Create a :class:`logging.handlers.RotatingFileHandler`.
150     """
151     rotating_file = logging_handlers.RotatingFileHandler(
152         filename=file_path,
153         maxBytes=max_bytes,
154         backupCount=backup_count,
155         delay=True,
156     )
157     rotating_file.setLevel(level)
158     rotating_file.formatter = formatter or _default_file_formatter
159     return rotating_file
160
161
162 class _SQLAlchemyHandler(logging.Handler):
163     def __init__(self, model, log_cls, execution_id, **kwargs):
164         logging.Handler.__init__(self, **kwargs)
165         self._model = model
166         self._cls = log_cls
167         self._execution_id = execution_id
168
169     def emit(self, record):
170         created_at = datetime.strptime(logging.Formatter('%(asctime)s').formatTime(record),
171                                        '%Y-%m-%d %H:%M:%S,%f')
172         log = self._cls(
173             execution_fk=self._execution_id,
174             task_fk=record.task_id,
175             level=record.levelname,
176             msg=str(record.msg),
177             created_at=created_at,
178
179             # Not mandatory.
180             traceback=getattr(record, 'traceback', None)
181         )
182         self._model.log.put(log)
183
184
185 _default_file_formatter = logging.Formatter(
186     '%(asctime)s [%(name)s:%(levelname)s] %(message)s <%(pathname)s:%(lineno)d>')