xref: /llvm-project/lldb/examples/summaries/cocoa/Logger.py (revision 2238dcc39358353cac21df75c3c3286ab20b8f53)
1import sys
2import os.path
3import inspect
4
5
6class NopLogger:
7    def __init__(self):
8        pass
9
10    def write(self, data):
11        pass
12
13    def flush(self):
14        pass
15
16    def close(self):
17        pass
18
19
20class StdoutLogger:
21    def __init__(self):
22        pass
23
24    def write(self, data):
25        print(data)
26
27    def flush(self):
28        pass
29
30    def close(self):
31        pass
32
33
34class FileLogger:
35    def __init__(self, name):
36        self.file = None
37        try:
38            name = os.path.abspath(name)
39            self.file = open(name, "a")
40        except:
41            try:
42                self.file = open("formatters.log", "a")
43            except:
44                pass
45
46    def write(self, data):
47        if self.file is not None:
48            print(data, file=self.file)
49        else:
50            print(data)
51
52    def flush(self):
53        if self.file is not None:
54            self.file.flush()
55
56    def close(self):
57        if self.file is not None:
58            self.file.close()
59            self.file = None
60
61
62# to enable logging:
63# define lldb.formatters.Logger._lldb_formatters_debug_level to any number greater than 0
64# if you define it to any value greater than 1, the log will be automatically flushed after each write (slower but should make sure most of the stuff makes it to the log even if we crash)
65# if you define it to any value greater than 2, the calling function's details will automatically be logged (even slower, but provides additional details)
66# if you need the log to go to a file instead of on screen, define
67# lldb.formatters.Logger._lldb_formatters_debug_filename to a valid
68# filename
69
70
71class Logger:
72    def __init__(self, autoflush=False, logcaller=False):
73        global _lldb_formatters_debug_level
74        global _lldb_formatters_debug_filename
75        self.autoflush = autoflush
76        want_log = False
77        try:
78            want_log = _lldb_formatters_debug_level > 0
79        except:
80            pass
81        if not (want_log):
82            self.impl = NopLogger()
83            return
84        want_file = False
85        try:
86            want_file = (
87                _lldb_formatters_debug_filename is not None
88                and _lldb_formatters_debug_filename != ""
89                and _lldb_formatters_debug_filename != 0
90            )
91        except:
92            pass
93        if want_file:
94            self.impl = FileLogger(_lldb_formatters_debug_filename)
95        else:
96            self.impl = StdoutLogger()
97        try:
98            self.autoflush = _lldb_formatters_debug_level > 1
99        except:
100            self.autoflush = autoflush
101        want_caller_info = False
102        try:
103            want_caller_info = _lldb_formatters_debug_level > 2
104        except:
105            pass
106        if want_caller_info:
107            self._log_caller()
108
109    def _log_caller(self):
110        caller = inspect.stack()[2]
111        try:
112            if caller is not None and len(caller) > 3:
113                self.write("Logging from function " + str(caller))
114            else:
115                self.write(
116                    "Caller info not available - Required caller logging not possible"
117                )
118        finally:
119            del caller  # needed per Python docs to avoid keeping objects alive longer than we care
120
121    def write(self, data):
122        self.impl.write(data)
123        if self.autoflush:
124            self.flush()
125
126    def __rshift__(self, data):
127        self.write(data)
128
129    def flush(self):
130        self.impl.flush()
131
132    def close(self):
133        self.impl.close()
134