SpecLog 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- speclog-0.0.1/PKG-INFO +19 -0
- speclog-0.0.1/README.md +2 -0
- speclog-0.0.1/SpecLog/SpecLog.py +277 -0
- speclog-0.0.1/SpecLog/SpecLogger.py +128 -0
- speclog-0.0.1/SpecLog/__init__.py +5 -0
- speclog-0.0.1/SpecLog/config/__init__.py +0 -0
- speclog-0.0.1/SpecLog/config/config.py +93 -0
- speclog-0.0.1/SpecLog/debugLog.py +36 -0
- speclog-0.0.1/SpecLog/device.py +156 -0
- speclog-0.0.1/SpecLog/loggerConfig.py +190 -0
- speclog-0.0.1/SpecLog/monitor.py +1023 -0
- speclog-0.0.1/SpecLog/ui/__init__.py +0 -0
- speclog-0.0.1/SpecLog/ui/plotting.py +297 -0
- speclog-0.0.1/SpecLog/ui/plotting.ui +557 -0
- speclog-0.0.1/SpecLog/version.py +1 -0
- speclog-0.0.1/SpecLog.egg-info/PKG-INFO +19 -0
- speclog-0.0.1/SpecLog.egg-info/SOURCES.txt +21 -0
- speclog-0.0.1/SpecLog.egg-info/dependency_links.txt +1 -0
- speclog-0.0.1/SpecLog.egg-info/entry_points.txt +7 -0
- speclog-0.0.1/SpecLog.egg-info/requires.txt +6 -0
- speclog-0.0.1/SpecLog.egg-info/top_level.txt +1 -0
- speclog-0.0.1/pyproject.toml +50 -0
- speclog-0.0.1/setup.cfg +4 -0
speclog-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: SpecLog
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: A Python Package for logging data from instrumentations
|
|
5
|
+
Author-email: Yen-Chun Huang <yen-chun.huang@bruker.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
Requires-Dist: matplotlib>=3.7.1
|
|
12
|
+
Requires-Dist: numpy>=1.24.3
|
|
13
|
+
Requires-Dist: PySide6>=6.9.0
|
|
14
|
+
Requires-Dist: pyqtgraph>=0.13.3
|
|
15
|
+
Requires-Dist: spinlab>=1.1.3
|
|
16
|
+
Requires-Dist: pyserial>=3.5
|
|
17
|
+
|
|
18
|
+
# SpecLog
|
|
19
|
+
Python Package for Spectrometer Logging
|
speclog-0.0.1/README.md
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SpecLog: The logging program for instrumentations
|
|
3
|
+
|
|
4
|
+
SpecLog: read configurations, get available devices, send command and save return.
|
|
5
|
+
|
|
6
|
+
Author: Yen-Chun Huang
|
|
7
|
+
|
|
8
|
+
Company: Bridge 12 Technologies, Inc
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from .device import *
|
|
12
|
+
import time
|
|
13
|
+
import datetime
|
|
14
|
+
import os
|
|
15
|
+
from .loggerConfig import *
|
|
16
|
+
from .debugLog import *
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class SpecLog:
|
|
20
|
+
def __init__(self, config_file: str = None):
|
|
21
|
+
self.config = loggerConfig(config_file)
|
|
22
|
+
self.debugLogger = debugLog(config_file).logger
|
|
23
|
+
self.settings = self.config.settings
|
|
24
|
+
self.commands = (
|
|
25
|
+
self.config.commands
|
|
26
|
+
) # dictionary {model: {variable: {command, alias, min, max, static}}}
|
|
27
|
+
self.device_config = self.config.devices
|
|
28
|
+
|
|
29
|
+
self.log_dir = self.settings["log_folder_location"] + "/LOG/"
|
|
30
|
+
self._checkDirectory()
|
|
31
|
+
|
|
32
|
+
self.delay = int(self.settings["log_interval"])
|
|
33
|
+
self.max_size = int(self.settings["save_file_size_kb"])
|
|
34
|
+
|
|
35
|
+
self.connectDevices()
|
|
36
|
+
self.reconnectDevices()
|
|
37
|
+
|
|
38
|
+
self.data_by_variable = self._getDataDictByVariable(
|
|
39
|
+
self.commands
|
|
40
|
+
) # initial empty dictionary for storing data
|
|
41
|
+
|
|
42
|
+
self.header = self._makeLogHeader()
|
|
43
|
+
self.last_query_time = None
|
|
44
|
+
self.current_log_file = None
|
|
45
|
+
self.warning = 0
|
|
46
|
+
|
|
47
|
+
def log(self):
|
|
48
|
+
"""
|
|
49
|
+
Send command to a valid device, analyze return and save data to log file
|
|
50
|
+
|
|
51
|
+
It runs one time only.
|
|
52
|
+
"""
|
|
53
|
+
# if not self.current_log_file:
|
|
54
|
+
# self.debugLogger.info("new log file created")
|
|
55
|
+
# self._createNewLog()
|
|
56
|
+
|
|
57
|
+
now = time.time()
|
|
58
|
+
if self.reconnectDevices(): # check the device connections
|
|
59
|
+
self.debugLogger.info("A device is reconnected")
|
|
60
|
+
if not self.last_query_time or now - self.last_query_time > self.delay:
|
|
61
|
+
warning_level = 0
|
|
62
|
+
self._setTimeInDataDictByVariable() # update time
|
|
63
|
+
devices_info = (
|
|
64
|
+
self.devices.devices_info
|
|
65
|
+
) # dictionary: {model: {status, config_status, device, id_command}}
|
|
66
|
+
for name, info in self.commands.items():
|
|
67
|
+
delimiter = self.device_config[name]["delimiter"]
|
|
68
|
+
index = self.device_config[name]["index"]
|
|
69
|
+
device = devices_info[name]["device"]
|
|
70
|
+
termination = self.device_config[name]["termination"]
|
|
71
|
+
for variable in info.keys():
|
|
72
|
+
info[variable]['min'], info[variable]['max'], info[variable]['static']
|
|
73
|
+
if self.devices.checkDeviceStatus(
|
|
74
|
+
name
|
|
75
|
+
): # check the connection of a device
|
|
76
|
+
try:
|
|
77
|
+
command = info[variable]["command"]
|
|
78
|
+
device.write((command+termination).encode()) # send command to device
|
|
79
|
+
data_string = device.read_until(termination.encode()).decode()
|
|
80
|
+
data = self._returnStringConverter(
|
|
81
|
+
data_string, delimiter, index
|
|
82
|
+
)
|
|
83
|
+
except Exception as err:
|
|
84
|
+
self.devices.device_info["status"] = False
|
|
85
|
+
data = "nan"
|
|
86
|
+
|
|
87
|
+
else:
|
|
88
|
+
data = "nan" # write nan to not available data
|
|
89
|
+
self.data_by_variable[variable] = data
|
|
90
|
+
|
|
91
|
+
# check warning
|
|
92
|
+
if data == "nan":
|
|
93
|
+
warning_level = 2
|
|
94
|
+
|
|
95
|
+
elif info[variable]['static'] and float(data) != info[variable]['static']:
|
|
96
|
+
warning_level = 2
|
|
97
|
+
|
|
98
|
+
else:
|
|
99
|
+
if info[variable]['min']:
|
|
100
|
+
if float(data) <= info[variable]['min'] * 1.05:
|
|
101
|
+
warning_level = max(warning_level, 1)
|
|
102
|
+
elif float(data) < info[variable]['min']:
|
|
103
|
+
warning_level = 2
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
if info[variable]['max']:
|
|
107
|
+
if float(data) >= info[variable]['max'] * 0.95:
|
|
108
|
+
warning_level = max(warning_level, 1)
|
|
109
|
+
elif float(data) > info[variable]['max']:
|
|
110
|
+
warning_level = 2
|
|
111
|
+
self.warning = warning_level
|
|
112
|
+
|
|
113
|
+
self.last_query_time = now
|
|
114
|
+
|
|
115
|
+
# if self._checkFileSize(): # exceed the maximum file size
|
|
116
|
+
# if self._createNewLog(): # create log with header
|
|
117
|
+
# self.debugLogger.info("File size exceed, new log file created")
|
|
118
|
+
|
|
119
|
+
self._saveData()
|
|
120
|
+
|
|
121
|
+
def connectDevices(self):
|
|
122
|
+
"""
|
|
123
|
+
Call DEVICE
|
|
124
|
+
"""
|
|
125
|
+
self.devices = DEVICE(self.config, self.debugLogger) # establish communication
|
|
126
|
+
self.devices._getPorts()
|
|
127
|
+
self.available_addresses = self.devices.deviceAddresses
|
|
128
|
+
return True
|
|
129
|
+
|
|
130
|
+
def reconnectDevices(self):
|
|
131
|
+
restart_DEVICE = False
|
|
132
|
+
self.devices._getPorts()
|
|
133
|
+
for name in self.device_config.keys():
|
|
134
|
+
address = self.device_config[name]["address"]
|
|
135
|
+
|
|
136
|
+
if (
|
|
137
|
+
address not in self.devices.deviceAddresses
|
|
138
|
+
and address in self.available_addresses
|
|
139
|
+
): # when a connection is loss
|
|
140
|
+
# This step is to prevent the moment when the device is shown in the resource manager but connection fails
|
|
141
|
+
self.available_addresses.remove(address)
|
|
142
|
+
|
|
143
|
+
if (
|
|
144
|
+
address in self.devices.deviceAddresses
|
|
145
|
+
and address not in self.available_addresses
|
|
146
|
+
and not self.devices.devices_info[name]["status"]
|
|
147
|
+
):
|
|
148
|
+
restart_DEVICE = True
|
|
149
|
+
|
|
150
|
+
if restart_DEVICE:
|
|
151
|
+
del self.devices # delete the DEVICE class
|
|
152
|
+
return self.connectDevices()
|
|
153
|
+
|
|
154
|
+
else:
|
|
155
|
+
return False
|
|
156
|
+
|
|
157
|
+
def _checkDirectory(self):
|
|
158
|
+
if not os.path.exists(self.log_dir):
|
|
159
|
+
os.mkdir(self.log_dir)
|
|
160
|
+
return False
|
|
161
|
+
return True
|
|
162
|
+
|
|
163
|
+
def _findLog(self):
|
|
164
|
+
"""
|
|
165
|
+
Find current log file
|
|
166
|
+
|
|
167
|
+
"""
|
|
168
|
+
today = datetime.datetime.now().strftime("%Y%m%d") # YYYYMMDD
|
|
169
|
+
self.current_log_file = self.log_dir + "/log_" + today + ".csv"
|
|
170
|
+
|
|
171
|
+
return "log_" + today + ".csv" in os.listdir(self.log_dir)
|
|
172
|
+
|
|
173
|
+
def _createNewLog(self):
|
|
174
|
+
"""
|
|
175
|
+
Create new log file in log directory
|
|
176
|
+
"""
|
|
177
|
+
# now = datetime.datetime.now().strftime("%Y%m%d%H%M%S") # YYYYMMDDHMS
|
|
178
|
+
|
|
179
|
+
with open(self.current_log_file, "w") as f:
|
|
180
|
+
f.write(self.header)
|
|
181
|
+
|
|
182
|
+
return True
|
|
183
|
+
|
|
184
|
+
def _makeLogHeader(self):
|
|
185
|
+
"""
|
|
186
|
+
Make a log header base on the data by variable dictionary
|
|
187
|
+
|
|
188
|
+
Return:
|
|
189
|
+
header (str) format: 'Date, Time, variable 1, variable 2.....'
|
|
190
|
+
"""
|
|
191
|
+
list_of_items = list(self.data_by_variable.keys())
|
|
192
|
+
header = ", ".join(list_of_items) + "\n"
|
|
193
|
+
|
|
194
|
+
return header
|
|
195
|
+
|
|
196
|
+
def _saveData(self):
|
|
197
|
+
"""
|
|
198
|
+
Save current data to current log file
|
|
199
|
+
|
|
200
|
+
"""
|
|
201
|
+
list_of_data = list(self.data_by_variable.values())
|
|
202
|
+
data_string = ", ".join(list_of_data) + "\n"
|
|
203
|
+
|
|
204
|
+
if not self._findLog():
|
|
205
|
+
self._createNewLog()
|
|
206
|
+
with open(self.current_log_file, "a") as f:
|
|
207
|
+
f.write(data_string)
|
|
208
|
+
|
|
209
|
+
return True
|
|
210
|
+
|
|
211
|
+
# def _checkFileSize(self):
|
|
212
|
+
# """
|
|
213
|
+
# Check the size of file
|
|
214
|
+
|
|
215
|
+
# Return:
|
|
216
|
+
# bool: True if file is oversize
|
|
217
|
+
# """
|
|
218
|
+
# if os.path.getsize(self.current_log_file) > self.max_size * 1024:
|
|
219
|
+
# return True
|
|
220
|
+
# else:
|
|
221
|
+
# return False
|
|
222
|
+
|
|
223
|
+
def _getDataDictByVariable(self, command_dict: dict):
|
|
224
|
+
"""
|
|
225
|
+
Get the variable list based on the model and it's command dictionary
|
|
226
|
+
Args:
|
|
227
|
+
command_dict (dict): the command list for a device, {variable: {command, alias, min, max, static}}
|
|
228
|
+
|
|
229
|
+
Returns:
|
|
230
|
+
data_dict (dict): the data dictionary in format {variable: reading}
|
|
231
|
+
|
|
232
|
+
"""
|
|
233
|
+
today = str(datetime.date.today())
|
|
234
|
+
now = str(datetime.datetime.now().strftime("%H:%M:%S"))
|
|
235
|
+
data_dict = {"Date": today, "Time": now}
|
|
236
|
+
for info in command_dict.values():
|
|
237
|
+
temp_dict = {key: None for key in info}
|
|
238
|
+
data_dict = {**data_dict, **temp_dict}
|
|
239
|
+
|
|
240
|
+
return data_dict
|
|
241
|
+
|
|
242
|
+
def _returnStringConverter(self, string: str, delimiter: str, index: int):
|
|
243
|
+
"""
|
|
244
|
+
Convert returned string and acquire data from it
|
|
245
|
+
Args:
|
|
246
|
+
delimiter (str): the delimiter for string analysis
|
|
247
|
+
index (int): the data index
|
|
248
|
+
|
|
249
|
+
Returns:
|
|
250
|
+
data (string): return data in str
|
|
251
|
+
"""
|
|
252
|
+
try:
|
|
253
|
+
if delimiter:
|
|
254
|
+
data = string.split(delimiter)[index]
|
|
255
|
+
else:
|
|
256
|
+
data = string.split()[index]
|
|
257
|
+
data = data.replace(" ", "") # remove white space
|
|
258
|
+
data = data.replace("\n", "")
|
|
259
|
+
data = data.replace("\t", "")
|
|
260
|
+
data = data.replace("\r", "")
|
|
261
|
+
data = data.strip()
|
|
262
|
+
except:
|
|
263
|
+
self.debugLogger.error("String Convert Fail: recived: %s, delimiter: %s, index: %s" %(string, delimiter, index))
|
|
264
|
+
return data
|
|
265
|
+
|
|
266
|
+
def _setTimeInDataDictByVariable(self):
|
|
267
|
+
"""
|
|
268
|
+
Update the time in data dictionary by variable
|
|
269
|
+
"""
|
|
270
|
+
today = str(datetime.date.today())
|
|
271
|
+
now = str(datetime.datetime.now().strftime("%H:%M:%S"))
|
|
272
|
+
self.data_by_variable["Date"] = today
|
|
273
|
+
self.data_by_variable["Time"] = now
|
|
274
|
+
return True
|
|
275
|
+
|
|
276
|
+
# if __name__ == '__main__':
|
|
277
|
+
# SpecLog()
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This is the python program to control pyB12logger
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import sys
|
|
7
|
+
import argparse
|
|
8
|
+
import shutil
|
|
9
|
+
import subprocess
|
|
10
|
+
from collections import Counter
|
|
11
|
+
from .SpecLog import *
|
|
12
|
+
|
|
13
|
+
# auto start and adding icon to desktop (public)
|
|
14
|
+
startup_folder = os.path.join(
|
|
15
|
+
os.environ["APPDATA"],
|
|
16
|
+
r"Microsoft\Windows\Start Menu\Programs\Startup"
|
|
17
|
+
)
|
|
18
|
+
desktop_folder = os.path.join(os.environ["USERPROFILE"], "Desktop")
|
|
19
|
+
|
|
20
|
+
source_running_logger = os.path.join(
|
|
21
|
+
os.path.dirname(sys.executable), "scripts", "SpecLogger_running.exe"
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
source_monitor = os.path.join(
|
|
25
|
+
os.path.dirname(sys.executable), "scripts", "pymonitor.exe"
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
def main_func():
|
|
29
|
+
parser = argparse.ArgumentParser(prog="SpecLogger")
|
|
30
|
+
parser.add_argument(
|
|
31
|
+
"status",
|
|
32
|
+
type=str,
|
|
33
|
+
nargs="?",
|
|
34
|
+
default=None,
|
|
35
|
+
choices=["start", "stop"],
|
|
36
|
+
help="To start/stop SpecLogger. If no argument, the SpecLogger will start by default",
|
|
37
|
+
)
|
|
38
|
+
parser.add_argument(
|
|
39
|
+
"-desktop",
|
|
40
|
+
type=str,
|
|
41
|
+
default=False,
|
|
42
|
+
choices=["True", "False"],
|
|
43
|
+
help="To create desktop icons",
|
|
44
|
+
)
|
|
45
|
+
parser.add_argument(
|
|
46
|
+
"-startup",
|
|
47
|
+
type=str,
|
|
48
|
+
default=None,
|
|
49
|
+
choices=["True", "False"],
|
|
50
|
+
help="To enable/disable SpecLogger at startup.",
|
|
51
|
+
)
|
|
52
|
+
parser.add_argument(
|
|
53
|
+
"-debug",
|
|
54
|
+
type=str,
|
|
55
|
+
default="False",
|
|
56
|
+
choices=["True", "False"],
|
|
57
|
+
help="To start debug console SpecLogger.",
|
|
58
|
+
)
|
|
59
|
+
args = parser.parse_args()
|
|
60
|
+
|
|
61
|
+
if args.startup == "True":
|
|
62
|
+
target = os.path.join(startup_folder, "SpecLogger_running.exe")
|
|
63
|
+
if not os.path.exists(target):
|
|
64
|
+
shutil.copy(source_running_logger, target)
|
|
65
|
+
print("SpecLogger will run on startup.")
|
|
66
|
+
elif args.startup == "False":
|
|
67
|
+
if not os.path.exists(startup_folder + "/SpecLogger_running.exe"):
|
|
68
|
+
print(startup_folder + "SpecLogger_running.exe")
|
|
69
|
+
print("SpecLogger does not run on startup.")
|
|
70
|
+
else:
|
|
71
|
+
os.remove(startup_folder + "/SpecLogger_running.exe")
|
|
72
|
+
print("SpecLogger will not run on startup.")
|
|
73
|
+
|
|
74
|
+
if args.desktop == "True":
|
|
75
|
+
target_logger = os.path.join(desktop_folder, "SpecLogger_running.exe")
|
|
76
|
+
target_monitor = os.path.join(desktop_folder, "pymonitor.exe")
|
|
77
|
+
|
|
78
|
+
if not os.path.exists(target_logger):
|
|
79
|
+
shutil.copy(source_running_logger, target_logger)
|
|
80
|
+
print("Create SpecLogger_running.exe on the desktop.")
|
|
81
|
+
else:
|
|
82
|
+
print("SpecLogger_running.exe is on desktop already.")
|
|
83
|
+
|
|
84
|
+
if not os.path.exists(target_monitor):
|
|
85
|
+
shutil.copy(source_monitor, target_monitor)
|
|
86
|
+
print("Create pymonitor.exe on the desktop.")
|
|
87
|
+
else:
|
|
88
|
+
print("pymonitor.exe is on desktop already.")
|
|
89
|
+
|
|
90
|
+
if not args.startup and not args.desktop and not args.status: # not arguments
|
|
91
|
+
args.status = "start"
|
|
92
|
+
|
|
93
|
+
if args.status == "start":
|
|
94
|
+
current_exe = (
|
|
95
|
+
os.popen("wmic process get description")
|
|
96
|
+
.read()
|
|
97
|
+
.strip()
|
|
98
|
+
.replace(" ", "")
|
|
99
|
+
.split("\n\n")
|
|
100
|
+
)
|
|
101
|
+
hashDict = Counter(current_exe)
|
|
102
|
+
|
|
103
|
+
if (
|
|
104
|
+
"SpecLogger_running.exe" in hashDict
|
|
105
|
+
and hashDict["SpecLogger_running.exe"] > 0
|
|
106
|
+
):
|
|
107
|
+
print("SpecLogger has started already.")
|
|
108
|
+
return
|
|
109
|
+
|
|
110
|
+
else:
|
|
111
|
+
if args.debug == "False":
|
|
112
|
+
subprocess.Popen(
|
|
113
|
+
"SpecLogger_running.exe", creationflags=subprocess.CREATE_NO_WINDOW
|
|
114
|
+
)
|
|
115
|
+
print("SpecLogger started")
|
|
116
|
+
elif args.debug == "True":
|
|
117
|
+
os.startfile("SpecLogger_running.exe")
|
|
118
|
+
print("SpecLogger debug mode started")
|
|
119
|
+
|
|
120
|
+
elif args.status == "stop":
|
|
121
|
+
os.system("taskkill /im SpecLogger_running.exe /F /t")
|
|
122
|
+
print("SpecLogger stopped")
|
|
123
|
+
else: # ignore
|
|
124
|
+
return
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
if __name__ == "__main__":
|
|
128
|
+
main_func()
|
|
File without changes
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""
|
|
2
|
+
global config
|
|
3
|
+
"""
|
|
4
|
+
import configparser
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
import warnings
|
|
7
|
+
import os
|
|
8
|
+
import shutil
|
|
9
|
+
|
|
10
|
+
import logging
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _escape_split(s, delim=",", escape="\\"):
|
|
16
|
+
tokens = []
|
|
17
|
+
previous_escape = False
|
|
18
|
+
subtoken = ""
|
|
19
|
+
for k in range(len(s)):
|
|
20
|
+
if s[k] == delim and (not previous_escape):
|
|
21
|
+
if len(subtoken) > 0:
|
|
22
|
+
tokens.append(subtoken)
|
|
23
|
+
subtoken = "" # reset subtoken
|
|
24
|
+
else:
|
|
25
|
+
# ESCAPE DELIM -> DELIM
|
|
26
|
+
if previous_escape and s[k] != escape and s[k] == delim:
|
|
27
|
+
subtoken = subtoken[:-1] + s[k]
|
|
28
|
+
else:
|
|
29
|
+
# add to subtoken
|
|
30
|
+
subtoken += s[k]
|
|
31
|
+
# set previous_escape flag:
|
|
32
|
+
# If for current char is escape (True and s[k]=='\\') and previous_escape is False -> set it to True
|
|
33
|
+
# If for current char is escape (True and s[k]=='\\') and previous_escape is True -> case of '\\\\' -> escaping an escape character -> set it back to False
|
|
34
|
+
# if current char is no escape character -> set it to false
|
|
35
|
+
previous_escape = (not previous_escape) and (s[k] == escape)
|
|
36
|
+
if len(subtoken) > 0:
|
|
37
|
+
tokens.append(subtoken)
|
|
38
|
+
return tokens
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _kwarg_converter(s: str):
|
|
42
|
+
tokens = _escape_split(s, ",", escape="\\")
|
|
43
|
+
args = []
|
|
44
|
+
kwargs = {}
|
|
45
|
+
for k in tokens:
|
|
46
|
+
subtokens = _escape_split(k, "=", escape="\\")
|
|
47
|
+
if len(subtokens) == 1:
|
|
48
|
+
args.append(subtokens[0])
|
|
49
|
+
else:
|
|
50
|
+
kwargs[subtokens[0].strip()] = subtokens[1].strip()
|
|
51
|
+
return args, kwargs
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _get_log_config(configname, key=None):
|
|
55
|
+
config = configparser.ConfigParser(
|
|
56
|
+
converters={
|
|
57
|
+
"list": lambda x: list(x.strip("[").strip("]").split(",")),
|
|
58
|
+
"args_kwargs": _kwarg_converter,
|
|
59
|
+
}
|
|
60
|
+
)
|
|
61
|
+
# define three possible locations:
|
|
62
|
+
log_current_config = Path.cwd() / configname
|
|
63
|
+
log_home_config = Path.home() / configname
|
|
64
|
+
|
|
65
|
+
log_cfg_folder = str(Path(__file__).parent) # / configname #.with_name("config"))
|
|
66
|
+
|
|
67
|
+
log_global_config = Path(log_cfg_folder) / configname
|
|
68
|
+
|
|
69
|
+
if key == "public":
|
|
70
|
+
# copy command to public location
|
|
71
|
+
# check if command location
|
|
72
|
+
log_public = "C:/Users/Public/"
|
|
73
|
+
list_dir = os.listdir(log_public)
|
|
74
|
+
log_dir = log_public + "LOG_Config"
|
|
75
|
+
if "LOG_Config" not in list_dir:
|
|
76
|
+
os.mkdir(log_dir)
|
|
77
|
+
|
|
78
|
+
log_public_config = log_dir + "/" + configname
|
|
79
|
+
|
|
80
|
+
if configname not in os.listdir(log_dir):
|
|
81
|
+
shutil.copy(log_global_config, log_dir + "/" + configname)
|
|
82
|
+
|
|
83
|
+
config.read(log_public_config)
|
|
84
|
+
else:
|
|
85
|
+
config_read_list = [log_global_config, log_home_config, log_current_config]
|
|
86
|
+
|
|
87
|
+
# user defined takes precedence
|
|
88
|
+
config.read(config_read_list)
|
|
89
|
+
|
|
90
|
+
return config
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
CONFIG = _get_log_config("config.cfg", key="public")
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This is debug log class for logger
|
|
3
|
+
|
|
4
|
+
Author: Yen-Chun Huang
|
|
5
|
+
|
|
6
|
+
Company: Bridge 12 Technologies. Inc
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
from .loggerConfig import *
|
|
11
|
+
import os
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class debugLog:
|
|
15
|
+
def __init__(self, config_file: str = None):
|
|
16
|
+
config = loggerConfig(config_file)
|
|
17
|
+
settings = config.settings
|
|
18
|
+
log_dir = settings["log_folder_location"] + "/LOG/"
|
|
19
|
+
|
|
20
|
+
if not os.path.exists(log_dir):
|
|
21
|
+
os.mkdir(log_dir)
|
|
22
|
+
|
|
23
|
+
logpath = log_dir + "/debug_log.txt"
|
|
24
|
+
self.logger = logging.getLogger(__name__)
|
|
25
|
+
self.logger.setLevel(logging.DEBUG)
|
|
26
|
+
ch = logging.FileHandler(str(logpath))
|
|
27
|
+
ch.setLevel(logging.INFO)
|
|
28
|
+
ch2 = logging.StreamHandler()
|
|
29
|
+
ch2.setLevel(logging.DEBUG)
|
|
30
|
+
formatter = logging.Formatter(
|
|
31
|
+
"%(asctime)s - [%(filename)s:%(lineno)d] - %(levelname)s - %(message)s"
|
|
32
|
+
)
|
|
33
|
+
ch.setFormatter(formatter)
|
|
34
|
+
ch2.setFormatter(formatter)
|
|
35
|
+
self.logger.addHandler(ch)
|
|
36
|
+
self.logger.addHandler(ch2)
|