NFVBENCH-12 Add run summary to fluentd stream
[nfvbench.git] / nfvbench / fluentd.py
1 # Copyright 2017 Cisco Systems, Inc.  All rights reserved.
2 #
3 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
4 #    not use this file except in compliance with the License. You may obtain
5 #    a copy of the License at
6 #
7 #         http://www.apache.org/licenses/LICENSE-2.0
8 #
9 #    Unless required by applicable law or agreed to in writing, software
10 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 #    License for the specific language governing permissions and limitations
13 #    under the License.
14
15 from datetime import datetime
16 from fluent import sender
17 import logging
18
19
20 class FluentLogHandler(logging.Handler):
21     '''This is a minimalist log handler for use with Fluentd
22
23     Needs to be attached to a logger using the addHandler method.
24     It only picks up from every record:
25     - the formatted message (no timestamp and no level)
26     - the level name
27     - the runlogdate (to tie multiple run-related logs together)
28     The timestamp is retrieved by the fluentd library.
29     '''
30
31     def __init__(self, tag, fluentd_ip='127.0.0.1', fluentd_port=24224):
32         logging.Handler.__init__(self)
33         self.tag = tag
34         self.formatter = logging.Formatter('%(message)s')
35         self.sender = sender.FluentSender(self.tag, host=fluentd_ip, port=fluentd_port)
36         self.runlogdate = 0
37         self.__warning_counter = 0
38         self.__error_counter = 0
39
40     def start_new_run(self):
41         '''Delimitate a new run in the stream of records with a new timestamp
42         '''
43         self.runlogdate = str(datetime.now())
44         # reset counters
45         self.__warning_counter = 0
46         self.__error_counter = 0
47         # send start record
48         self.__send_start_record()
49
50     def emit(self, record):
51         data = {
52             "runlogdate": self.runlogdate,
53             "loglevel": record.levelname,
54             "message": self.formatter.format(record)
55         }
56         self.__update_stats(record.levelno)
57         self.sender.emit(None, data)
58
59     # send START record for each run
60     def __send_start_record(self):
61         data = {
62             "runlogdate": self.runlogdate,
63             "loglevel": "START",
64             "message": "NFVBENCH run is started",
65             "numloglevel": 0,
66             "numerrors": 0,
67             "numwarnings": 0
68         }
69         self.sender.emit(None, data)
70
71     # send stats related to the current run and reset state for a new run
72     def send_run_summary(self, run_summary_required):
73         if run_summary_required or self.__get_highest_level() == logging.ERROR:
74             data = {
75                 "runlogdate": self.runlogdate,
76                 "loglevel": "RUN_SUMMARY",
77                 "message": self.__get_highest_level_desc(),
78                 "numloglevel": self.__get_highest_level(),
79                 "numerrors": self.__error_counter,
80                 "numwarnings": self.__warning_counter
81             }
82             self.sender.emit(None, data)
83
84     def __get_highest_level(self):
85         if self.__error_counter > 0:
86             return logging.ERROR
87         elif self.__warning_counter > 0:
88             return logging.WARNING
89         return logging.INFO
90
91     def __get_highest_level_desc(self):
92         highest_level = self.__get_highest_level()
93         if highest_level == logging.INFO:
94             return "GOOD RUN"
95         elif highest_level == logging.WARNING:
96             return "RUN WITH WARNINGS"
97         else:
98             return "RUN WITH ERRORS"
99
100     def __update_stats(self, levelno):
101         if levelno == logging.WARNING:
102             self.__warning_counter += 1
103         elif levelno == logging.ERROR:
104             self.__error_counter += 1