forked from robcarver17/pysystemtrade
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlog_to_file.py
150 lines (114 loc) · 4.09 KB
/
log_to_file.py
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
import os
from os.path import join as join_file_and_path
from syscore.constants import missing_data, missing_file
from syscore.fileutils import get_resolved_pathname, does_resolved_filename_exist
from sysdata.config.production_config import get_production_config
from syslogdiag.pst_logger import pst_logger, DEFAULT_LOG_LEVEL
from syslogdiag.log_entry import logEntry
from syslogdiag.email_via_db_interface import send_production_mail_msg
EMAIL_ON_LOG_LEVEL = [4]
LINES_TO_FLUSH_AFTER = 5
class logToFile(pst_logger):
"""
Logs to a file, named after type
"""
def __init__(
self,
type,
data: "dataBlob" = None,
log_level: str = DEFAULT_LOG_LEVEL,
**kwargs,
):
self.data = data
self._log_directory = get_logging_directory(data)
super().__init__(type=type, log_level=log_level, **kwargs)
def log_handle_caller(
self, msglevel: int, text: str, attributes: dict, log_id: int
):
"""
Ignores log_level - logs everything, just in case
Doesn't raise exceptions
"""
log_entry = logEntry(
text, msglevel=msglevel, attributes=attributes, log_id=log_id
)
print(log_entry)
self.log_to_file(log_entry)
if msglevel in EMAIL_ON_LOG_LEVEL:
# Critical, send an email
self.email_user(log_entry)
return log_entry
def log_to_file(self, log_entry: logEntry):
self.log_file_handle.write("%s\n" % str(log_entry))
self.check_if_ready_and_if_so_flush()
def check_if_ready_and_if_so_flush(self):
log_id = self.log_id
if (log_id % LINES_TO_FLUSH_AFTER) == 0:
self.log_file_handle.flush()
def get_next_log_id(self) -> int:
current_log_id = self.log_id
incremented_log_id = current_log_id + 1
self._logid = incremented_log_id
return incremented_log_id
@property
def log_id(self) -> int:
current_log_id = getattr(self, "_logid", None)
if current_log_id is None:
current_log_id = 0
self.log_id = current_log_id
return current_log_id
@log_id.setter
def log_id(self, log_id: int):
self._logid = log_id
def email_user(self, log_entry: logEntry):
data = self.data
subject_line = str(log_entry.attributes) + ": " + str(log_entry.text)
log_entry_text = str(log_entry)
send_production_mail_msg(
data, log_entry_text, "*CRITICAL* ERROR: %s" % subject_line
)
def close_log_file(self):
file_handle = getattr(self, "_file_handle", None)
if file_handle is None:
## no file, logging won't work
print("No log file open to close")
else:
file_handle.close()
## force reopen on new log
self._file_handle = missing_file
@property
def log_file_handle(self):
file_handle = getattr(self, "_file_handle", missing_file)
if file_handle is missing_file:
filename = self.log_filename_with_path
file_handle = open(filename, "a", 5)
self._file_handle = file_handle
return file_handle
@property
def log_filename_with_path(self) -> str:
log_directory = self.log_directory
log_type = self.type
log_filename = "log_%s.txt" % log_type
log_filename_and_path = join_file_and_path(log_directory, log_filename)
return log_filename_and_path
@property
def log_directory(self) -> str:
return self._log_directory
@property
def type(self) -> str:
return self.attributes["type"]
def get_logging_directory(data: "dataBlob"):
config = get_production_config()
log_dir = config.get_element_or_default("log_directory", None)
if log_dir is None:
## Can't log this but print anyway
print(
"*** log_directory undefined in private_config.yaml, will log to arbitrary directory"
)
return ""
log_dir = get_resolved_pathname(log_dir)
try:
os.mkdir(log_dir)
except:
pass
return log_dir