Skip to content

Commit 58c27e1

Browse files
authored
Merge pull request #1 from PabloLec/dev
Update 0.0.2
2 parents 12e99b9 + 564c923 commit 58c27e1

File tree

5 files changed

+286
-126
lines changed

5 files changed

+286
-126
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
__pycache__
1+
__pycache__/
22
poetry.lock
33
dev.py

livelog/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# -*- coding: utf-8 -*-
22

3-
from .logger import Logger
3+
from livelog.logger import Logger, LoggerSingleton

livelog/__main__.py

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,57 @@
11
# -*- coding: utf-8 -*-
22

3-
from sys import argv
4-
from os import _exit
5-
from .reader import start_reader
3+
from platform import system
4+
from tempfile import gettempdir
5+
from pathlib import Path
6+
from argparse import ArgumentParser
7+
from livelog.reader import start_reader
68

7-
if __name__ == "__main__":
8-
if len(argv) == 1:
9-
print("! No file specified !")
10-
_exit(1)
119

12-
start_reader(file=argv[1])
10+
def _parse_args():
11+
"""Parse CLI arguments.
12+
13+
Returns:
14+
tuple: Provided arguments
15+
"""
16+
17+
parser = ArgumentParser(description="Live read a log file")
18+
parser.add_argument(
19+
"-f",
20+
"--file",
21+
action="store",
22+
type=str,
23+
required=False,
24+
help="Log file to be read",
25+
)
26+
parser.add_argument(
27+
"-l",
28+
"--level",
29+
action="store",
30+
type=str,
31+
default="DEBUG",
32+
required=False,
33+
help="Minimum log level. Default: DEBUG",
34+
)
35+
parser.add_argument(
36+
"--nocolors",
37+
action="store_true",
38+
required=False,
39+
help="Do not color lines",
40+
)
41+
args = parser.parse_args()
42+
43+
if args.file is not None:
44+
file = Path(args.file)
45+
else:
46+
file = (
47+
Path("/tmp/livelog.log")
48+
if system() == "Darwin"
49+
else Path(gettempdir()) / "livelog.log"
50+
)
51+
52+
return file, args.level, args.nocolors
53+
54+
55+
if __name__ == "__main__":
56+
file, level, nocolors = _parse_args()
57+
start_reader(file=file, level=level, nocolors=nocolors)

livelog/logger.py

Lines changed: 58 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,18 @@
55
from platform import system
66
from tempfile import gettempdir
77
from datetime import datetime
8-
from colorama import Fore, Style
98
from .errors import *
109

1110

1211
class Logger:
13-
"""Main logger object.
12+
"""Logging handler.
13+
14+
Attributes:
15+
LEVELS (dict): Log levels value for fast filtering
16+
enabled (bool): If logging is enabled
17+
erase (bool): If preexisting file should be erased
18+
file (str): Log file path
19+
level (str): Minimum log level to be displayed
1420
1521
Raises:
1622
LogLevelDoesNotExist: If user provide an unknown log level
@@ -20,66 +26,57 @@ class Logger:
2026
write to output path
2127
"""
2228

23-
__instance = None
24-
_LEVELS = {"ERROR": 3, "WARNING": 2, "INFO": 1, "DEBUG": 0}
25-
26-
def __new__(cls, *args, **kwargs):
27-
is_singleton = (len(args) == 6 and args[5] == True) or kwargs.get("singleton")
28-
if is_singleton and not Logger.__instance or not is_singleton:
29-
Logger.__instance = object.__new__(cls)
30-
return Logger.__instance
29+
_LEVELS = {
30+
"ERROR": 3,
31+
"WARNING": 2,
32+
"INFO": 1,
33+
"DEBUG": 0,
34+
}
3135

3236
def __init__(
3337
self,
34-
output_file: str = None,
35-
level: str = "INFO",
38+
file: str = None,
39+
level: str = "DEBUG",
3640
enabled: bool = True,
37-
colors: bool = True,
3841
erase: bool = True,
39-
singleton: bool = False,
4042
):
4143
"""Logger initialization.
4244
4345
Args:
44-
output_file (str, optional): Output file path. Defaults to None.
45-
level (str, optional): Minimum log level. Defaults to "INFO".
46+
file (str, optional): Output file path. Defaults to None.
47+
level (str, optional): Minimum log level. Defaults to "DEBUG".
4648
enabled (bool, optional): Is log enabled ? Defaults to True.
47-
colors (bool, optional): Are colors enabled ? Defaults to True.
4849
erase (bool, optional): Should preexisting file be erased ? Defaults to True.
49-
singleton (bool, optional): Is singleton ? Defaults to False.
50-
51-
Raises:
52-
LogLevelDoesNotExist: [description]
5350
"""
5451

5552
self._enabled = enabled
56-
self._colors = colors
5753
self._erase = erase
5854

59-
if output_file is None:
60-
self._output_file = Path(
55+
if file is None:
56+
self._file = Path(
6157
"/tmp/livelog.log"
6258
if system() == "Darwin"
6359
else Path(gettempdir()) / "livelog.log"
6460
)
6561
else:
66-
self._output_file = Path(output_file)
67-
self._verify_file(self._output_file)
62+
self._file = Path(file)
63+
64+
self._verify_file()
6865

6966
level = level.upper()
7067
if level not in self._LEVELS:
7168
raise LogLevelDoesNotExist(level)
7269
self._level = level
7370

7471
@property
75-
def output_file(self):
76-
return self._output_file
72+
def file(self):
73+
return self._file
7774

78-
@output_file.setter
79-
def set_output_file(self, value: str):
75+
@file.setter
76+
def set_file(self, value: str):
8077
path = Path(value)
8178
self._verify_file(file=path)
82-
self._output_file = path
79+
self._file = path
8380

8481
@property
8582
def level(self):
@@ -92,16 +89,14 @@ def level(self, value: str):
9289
raise LogLevelDoesNotExist(level)
9390
self._level = level
9491

95-
def _verify_file(self, file: Path):
96-
"""Verify if the file is a valid log file and clear its preexisting content.
97-
98-
Args:
99-
file (Path): File path to verify.
92+
def _verify_file(self):
93+
"""Verify if provided file path is a valid log file and clear its
94+
preexisting content.
10095
"""
10196

102-
dir = file.parent.resolve()
103-
if file.is_dir():
104-
raise LogFileIsADirectory(path=file)
97+
dir = self._file.parent.resolve()
98+
if self._file.is_dir():
99+
raise LogFileIsADirectory(path=self._file)
105100
if not dir.is_dir():
106101
raise LogPathDoesNotExist(path=dir)
107102
if not access(dir, X_OK):
@@ -111,31 +106,26 @@ def _verify_file(self, file: Path):
111106
def _clear_file(self):
112107
"""Clear output file content."""
113108

114-
if not self._erase or not self._output_file.is_file():
109+
if not self._erase or not self._file.is_file():
115110
return
116-
with open(self._output_file, "w") as f:
111+
with open(self._file, "w") as f:
117112
pass
118113

119-
def _write(self, content: str):
114+
def _write(self, level: str, content: str):
120115
"""Write provided content to output file.
121116
122117
Args:
118+
level (str); Log level
123119
content (str): Content to be written
124120
"""
125121

126122
if not self._enabled:
127123
return
128124

129-
if self._colors:
130-
time = Style.DIM + datetime.now().strftime("%H:%M:%S.%f")[:-3]
131-
dash = Style.BRIGHT + " - "
132-
content = f"{Style.NORMAL}{content}{Style.RESET_ALL}"
133-
else:
134-
time = datetime.now().strftime("%H:%M:%S.%f")[:-3]
135-
dash = " - "
125+
time = datetime.now().strftime("%H:%M:%S.%f")[:-3]
136126

137-
with open(self._output_file, "a") as f:
138-
f.write(f"{time}{dash}{content}\n")
127+
with open(self._file, "a") as f:
128+
f.write(f"{level} | {time} - {content}\n")
139129

140130
def _is_valid_level(self, level: str):
141131
"""Verify if the given log level should be written.
@@ -156,10 +146,7 @@ def error(self, message: str):
156146
message (str): Log message
157147
"""
158148

159-
if self._colors:
160-
self._write(content=Fore.RED + message)
161-
else:
162-
self._write(content="error | " + message)
149+
self._write(level="ERR!", content=message)
163150

164151
def warn(self, message: str):
165152
"""Write warning message.
@@ -170,10 +157,7 @@ def warn(self, message: str):
170157

171158
if not self._is_valid_level("WARNING"):
172159
return
173-
if self._colors:
174-
self._write(content=Fore.YELLOW + message)
175-
else:
176-
self._write(content="warning | " + message)
160+
self._write(level="WARN", content=message)
177161

178162
def info(self, message: str):
179163
"""Write info message.
@@ -184,10 +168,7 @@ def info(self, message: str):
184168

185169
if not self._is_valid_level("INFO"):
186170
return
187-
if self._colors:
188-
self._write(content=Fore.BLUE + message)
189-
else:
190-
self._write(content="info | " + message)
171+
self._write(level="INFO", content=message)
191172

192173
def debug(self, message: str):
193174
"""Write debug message.
@@ -198,7 +179,17 @@ def debug(self, message: str):
198179

199180
if not self._is_valid_level("DEBUG"):
200181
return
201-
if self._colors:
202-
self._write(content=Fore.WHITE + message)
203-
else:
204-
self._write(content="debug | " + message)
182+
self._write(level="DBUG", content=message)
183+
184+
185+
class Singleton(type):
186+
_instances = {}
187+
188+
def __call__(cls, *args, **kwargs):
189+
if cls not in cls._instances:
190+
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
191+
return cls._instances[cls]
192+
193+
194+
class LoggerSingleton(Logger, metaclass=Singleton):
195+
pass

0 commit comments

Comments
 (0)