summaryrefslogtreecommitdiff
path: root/python/log/gnunet_log.py
blob: 9dc5e093ffc654c7900efe00193e506298cfeb24 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#!/usr/bin/env python3

# GNUNET_FORCE_LOG format [component];[file];[function];[from line [to line]];loglevel

import os
import logging

class LogDefinition:
    def __init__(self, component, forced, loglevel):

        self.component = component
        self.forced = forced
        # string here, comes from env after all.
        self.loglevel = loglevel

class GnunetLoglevel:
    def __init__(self, string, level, function):
        self.string = string
        self.level = level
        self.function = function

    def __str__(self):
        return self.string
    
    def getLevel(self):
        return self.level

    def getFunction(self):
        return self.function

class GnunetLogger:

    def __init__(self, component):
        self.logger = logging.getLogger(component)
        self.ERROR = GnunetLoglevel("ERROR", logging.ERROR, self.logger.error)
        self.WARNING = GnunetLoglevel("WARNING", logging.WARNING, self.logger.warning)
        self.INFO = GnunetLoglevel("INFO", logging.INFO, self.logger.info)
        self.DEBUG = GnunetLoglevel("DEBUG", logging.DEBUG, self.logger.debug)

        self.component = component
        self.loglevel = None

        # Setting the *logging* loglevel in order to have the
        # chance of changing the *logger* (object) loglevel along the
        # execution.  So this particular loglevel has no relevance
        # (might have been any other loglevel).
        logging.basicConfig(level=logging.INFO)

        self.no_forced_definitions = True
        self.definitions = list()

        if os.environ.get("GNUNET_LOG"):
            self.__parse_definitions(os.environ.get("GNUNET_LOG"), False)

        if os.environ.get("GNUNET_FORCE_LOG"):
            self.no_forced_definitions = False
            self.__parse_definitions(os.environ.get("GNUNET_FORCE_LOG"), True)

    def string_to_loglevel(self, level):
        
        level_map = {
            "ERROR": self.ERROR,
            "WARNING": self.WARNING,
            "INFO": self.INFO,
            "DEBUG": self.DEBUG}

        # Defaults to INFO.
        return level_map.get(level, self.INFO)

    def setup(self, loglevel):
        self.loglevel = loglevel

    def log(self, message, message_loglevel):

        # Ordinary case (level setup + nothing forced).
        if self.loglevel and self.no_forced_definitions:
            self.logger.setLevel(level=self.loglevel.getLevel())
            message_loglevel.getFunction()(message)
            return

        # We crawl through GNUNET_FORCE_LOG definitions,
        # or GNUNET_LOG (in case of non-forced definition
        # and non-given loglevel at object creation time)
        for defi in self.definitions:
            if defi.forced or not self.loglevel:
                # Temporarily checking only the component name.
                # To be extended with all the others definition-parts.
                if self.component == defi.component:
                    self.logger.setLevel(
                        level=self.string_to_loglevel(defi.loglevel).getLevel())
                    message_loglevel.getFunction()(message)
                    return

        # If the flow got here, then one of the following
        # may hold.
        #
        # (1) GNUNET_FORCE_LOG was given and no definition was
        #     found for this component (neither forced nor unforced).
        #     Possibly, there also exists a default loglevel.
        
        if self.loglevel:
            self.logger.setLevel(
                level=self.loglevel.getLevel())

        # (2) GNUNET_FORCE_LOG was NOT given and neither was
        #     a default loglevel, and also a unforced definition
        #     wasn't found.  Must assign a made-up loglevel.
        
        else:
            self.logger.setLevel(level=logging.INFO)

        message_loglevel.getFunction()(message)

    def __parse_definitions(self, line, forced):
        gfl_split = line.split("/")
        for component in gfl_split:
            gfl_split_split = component.split(";")

            if 5 != len(gfl_split_split):
                print("warning: GNUNET_(FORCE_)LOG is malformed")
                return

            definition = LogDefinition(gfl_split_split[0],
                                       forced,
                                       loglevel=gfl_split_split[4])

            self.definitions.append(definition)