1from __future__ import print_function
2import sys
3import os.path
4import inspect
5
6
7class NopLogger:
8
9    def __init__(self):
10        pass
11
12    def write(self, data):
13        pass
14
15    def flush(self):
16        pass
17
18    def close(self):
19        pass
20
21
22class StdoutLogger:
23
24    def __init__(self):
25        pass
26
27    def write(self, data):
28        print(data)
29
30    def flush(self):
31        pass
32
33    def close(self):
34        pass
35
36
37class FileLogger:
38
39    def __init__(self, name):
40        self.file = None
41        try:
42            name = os.path.abspath(name)
43            self.file = open(name, 'a')
44        except:
45            try:
46                self.file = open('formatters.log', 'a')
47            except:
48                pass
49
50    def write(self, data):
51        if self.file is not None:
52            print(data, file=self.file)
53        else:
54            print(data)
55
56    def flush(self):
57        if self.file is not None:
58            self.file.flush()
59
60    def close(self):
61        if self.file is not None:
62            self.file.close()
63            self.file = None
64
65# to enable logging:
66# define lldb.formatters.Logger._lldb_formatters_debug_level to any number greater than 0
67# 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)
68# 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)
69# if you need the log to go to a file instead of on screen, define
70# lldb.formatters.Logger._lldb_formatters_debug_filename to a valid
71# filename
72
73
74class Logger:
75
76    def __init__(self, autoflush=False, logcaller=False):
77        global _lldb_formatters_debug_level
78        global _lldb_formatters_debug_filename
79        self.autoflush = autoflush
80        want_log = False
81        try:
82            want_log = (_lldb_formatters_debug_level > 0)
83        except:
84            pass
85        if not (want_log):
86            self.impl = NopLogger()
87            return
88        want_file = False
89        try:
90            want_file = (_lldb_formatters_debug_filename is not None and _lldb_formatters_debug_filename !=
91                         '' and _lldb_formatters_debug_filename != 0)
92        except:
93            pass
94        if want_file:
95            self.impl = FileLogger(_lldb_formatters_debug_filename)
96        else:
97            self.impl = StdoutLogger()
98        try:
99            self.autoflush = (_lldb_formatters_debug_level > 1)
100        except:
101            self.autoflush = autoflush
102        want_caller_info = False
103        try:
104            want_caller_info = (_lldb_formatters_debug_level > 2)
105        except:
106            pass
107        if want_caller_info:
108            self._log_caller()
109
110    def _log_caller(self):
111        caller = inspect.stack()[2]
112        try:
113            if caller is not None and len(caller) > 3:
114                self.write('Logging from function ' + str(caller))
115            else:
116                self.write(
117                    'Caller info not available - Required caller logging not possible')
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