-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathJayTAKObjectLib.py
141 lines (115 loc) · 5.53 KB
/
JayTAKObjectLib.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
import os
import re
from datetime import datetime
# JayTAKObjLib
# Objects:
# Custom Exceptions:
# Custom exception to handle server response codes.
class WeatherServerException(Exception):
def __init__(self, errorCode, message="WeatherServerException: Received a code that was not 200. check README.md for more information."):
self.errorCode = errorCode
self.message = message
super().__init__(self.message, self.errorCode)
# Custom exception to handle invalid usage.
class UsageException(Exception):
def __init__(self, message="UsageException: Invalid Usage!"):
self.message = message
super().__init__(self.message)
# Other Objects:
# Date and time object.
class DTimeLive:
def getTime(self):
return datetime.now()
def getFormattedTime(self, dt):
return dt.strftime("[%H.%M.%S][%d-%m-%Y]")
def getLogFormattedTime(self, dt):
return dt.strftime("[%H:%M:%S][%d-%m-%Y]")
def getLocalFormattedTime(self, timestamp, timezoneOffset):
localTimeSeconds = timestamp + timezoneOffset
return datetime.utcfromtimestamp(localTimeSeconds).strftime("[%H:%M:%S][%d-%m-%Y]")
def getSunFormattedTime(self, timestamp, timezoneOffset):
localTimeSeconds = timestamp + timezoneOffset
return datetime.utcfromtimestamp(localTimeSeconds).strftime("%H:%M:%S")
# Logger Object.
class ActionLogger: # Levels in order: TRACE, DEBUG, INFO, NOTICE, WARN, ERROR, FATAL
def __init__(self, logFile="weatherAppActions.log"):
self.logFile = logFile
def logMsg(self, message, level="INFO"):
time = DTimeLive()
separator = " - "
match(level):
case "WARN" | "INFO":
separator = " --- "
case "ALERT" | "TRACE" | "DEBUG" | "ERROR" | "FATAL":
separator = " -- "
case "NOTICE":
separator = " - "
timestamp = time.getLogFormattedTime(time.getTime())
logEntry = f"{timestamp}[{level}]{separator}{message}\n"
with open(self.logFile, 'a') as file:
file.write(logEntry)
return
# Log prune object for logs folder and sub-folders.
class LogPruner:
def __init__(self, basePath, maxSeconds="21600"):
self.basePath = basePath
self.maxSeconds = maxSeconds
def pruneLogs(self):
KEY = True
names = ""
removedFiles = 0
logger = ActionLogger()
logger.logMsg(
f"Function 'LogPruner.pruneLogs' called with base path {self.basePath} and max seconds is set to {self.maxSeconds}")
time = datetime.now()
pattern = re.compile(r'(\w+)\[(\d+\.\d+\.\d+)\]\[(\d{2}-\d{2}-\d{4})\]\.json')
for filename in os.listdir(self.basePath):
filepath = os.path.join(self.basePath, filename)
if os.path.isfile(filepath):
fileMatch = pattern.match(filename)
if pattern.match(filename):
fileName, timeStr, dateStr = fileMatch.groups()
timestampStr = f"{dateStr} {timeStr}"
fileTime = datetime.strptime(timestampStr, "%d-%m-%Y %H.%M.%S")
timeDifference = time - fileTime
if timeDifference.total_seconds() > float(self.maxSeconds):
if KEY:
names += f"{filename}, "
removedFiles += 1
os.remove(filepath)
else:
logger.logMsg(f"Function 'LogPruner.pruneLogs' KEY disabled, unable to remove {filename}", "TRACE")
else:
logger.logMsg(
f"Function 'LogPruner.pruneLogs' File {filename} not old enough yet, current time: {time}, file time: {fileTime} time difference: {timeDifference}", "DEBUG")
else:
logger.logMsg(f"Function 'LogPruner.pruneLogs' file {filepath} does not match pattern", "DEBUG")
names = names.rstrip(", ")
logger.logMsg(f"Function 'LogPruner.pruneLogs' removed {removedFiles} file{'s' if removedFiles != 1 else ''}: {names}")
return removedFiles
# Log prune object for a single log file.
class LogFilePruner:
def __init__(self, filePath, maxLines="10000", pruneMultiplier="0.8"):
self.filePath = filePath
self.maxLines = int(maxLines)
self.pruneMultiplier = float(pruneMultiplier)
self.calculatedPrune = round(self.maxLines * self.pruneMultiplier)
def pruneLogFile(self):
logger = ActionLogger()
logger.logMsg(
f"Function 'LogFilePruner.pruneLogFile' called. Max Lines: {self.maxLines} Calculated-Prune: {self.calculatedPrune} Using Multiplier: {self.pruneMultiplier}", "INFO")
linesRemoved = 0
try:
with open(self.filePath, 'r') as file:
lines = file.readlines()
length = len(lines)
if length > self.maxLines:
linesToKeep = lines[length - self.calculatedPrune:]
with open(self.filePath, 'w') as file:
file.writelines(linesToKeep)
linesRemoved = length - len(linesToKeep)
logger.logMsg(
f"Function 'LogFilePruner.pruneLogFile' length of {self.filePath} was {length} which exceeded limit of {self.maxLines}. Removed {linesRemoved} lines and has been pruned to {len(linesToKeep)}, calculated with the multiplier: {self.pruneMultiplier}.", "INFO")
except Exception as e:
print(e)
return linesRemoved