logmachine 0.1.0__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.
File without changes
@@ -0,0 +1,17 @@
1
+ Metadata-Version: 2.4
2
+ Name: logmachine
3
+ Version: 0.1.0
4
+ Summary: Collaborative, beautiful logging system for distributed developers
5
+ Author-email: Mugabo Gusenga <mugabo@bufferpunk.com>
6
+ Project-URL: Homepage, https://github.com/Scion-Kin/logmachine
7
+ Project-URL: Documentation, https://github.com/Scion-Kin/logmachine#readme
8
+ Project-URL: Source, https://github.com/Scion-Kin/logmachine
9
+ Project-URL: Tracker, https://github.com/Scion-Kin/logmachine/issues
10
+ Keywords: logging,devtools,collaborative,open source,cli,json,ansi
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Operating System :: OS Independent
14
+ Requires-Python: >=3.7
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Dynamic: license-file
File without changes
@@ -0,0 +1,4 @@
1
+ from .core import (
2
+ ContribLog,
3
+ CustomFormatter,
4
+ )
@@ -0,0 +1,156 @@
1
+ import os, sys
2
+ import re
3
+ import json
4
+ import logging
5
+
6
+ class CustomFormatter(logging.Formatter):
7
+ COLORS = {
8
+ 'DEBUG': '\x1b[36m',
9
+ 'INFO': '\x1b[34m',
10
+ 'WARNING': '\x1b[33m',
11
+ 'ERROR': '\x1b[31m',
12
+ 'SUCCESS': '\x1b[32m'
13
+ }
14
+ RESET = '\x1b[0m'
15
+ BOLD = '\x1b[1m'
16
+ LEVEL_FORMATS = {
17
+ 'DEBUG': BOLD + '[DEBUG]' + RESET,
18
+ 'INFO': BOLD + '[INFO]' + RESET,
19
+ 'WARNING': BOLD + '[WARNING]' + RESET,
20
+ 'ERROR': BOLD + '[ERROR]' + RESET,
21
+ 'SUCCESS': BOLD + '[SUCCESS]' + RESET
22
+ }
23
+
24
+ def format(self, record):
25
+ try:
26
+ username = os.getlogin()
27
+ except Exception:
28
+ username = os.environ.get('USER', 'unknown')
29
+
30
+ levelname = record.levelname
31
+ color = self.COLORS.get(levelname, '')
32
+ level_fmt = self.LEVEL_FORMATS.get(levelname, f'[{levelname}]')
33
+ record.levelname = f"{color}{level_fmt}{self.RESET}"
34
+ record.asctime = self.formatTime(record, self.datefmt)
35
+ module_file = record.pathname
36
+ parent_dir = os.path.basename(os.path.dirname(module_file)) or 'unknown'
37
+
38
+ return f"""{self.COLORS.get('DEBUG')}({username}{self.RESET} @ {self.COLORS.get('WARNING') + parent_dir + self.RESET}) 🤌 CL Timing: {color}[ {record.asctime} ]{self.RESET}
39
+ {record.levelname} {record.getMessage()}
40
+ """
41
+
42
+ class ContribLog(logging.Logger):
43
+ SUCCESS = 25
44
+
45
+ def __init__(self, *args, **kwargs):
46
+ super().__init__(*args, **kwargs)
47
+ logging.addLevelName(self.SUCCESS, "SUCCESS")
48
+ self.log_file = kwargs.get('log_file', 'logs.log')
49
+ self.error_file = kwargs.get('error_file', 'errors.log')
50
+ self.verbose = kwargs.get('verbose', False)
51
+ self.debug_level = kwargs.get('debug_level', 0)
52
+ self.name = kwargs.get('name', 'CL Logger')
53
+
54
+ def success(self, msg, *args, **kwargs):
55
+ if self.isEnabledFor(self.SUCCESS):
56
+ self._log(self.SUCCESS, msg, args, **kwargs)
57
+
58
+ def get_logger(self):
59
+ # logger = logging.getLogger(self.name)
60
+ self.setLevel(logging.DEBUG)
61
+
62
+ # Remove existing handlers
63
+ self.handlers = []
64
+
65
+ # File handlers
66
+ fh = logging.FileHandler(self.log_file)
67
+ fh.setLevel(logging.DEBUG)
68
+ eh = logging.FileHandler(self.error_file)
69
+ eh.setLevel(logging.ERROR)
70
+
71
+ # Console handler
72
+ ch = logging.StreamHandler()
73
+ ch.setLevel(logging.DEBUG if self.verbose else logging.CRITICAL + 1)
74
+
75
+ formatter = CustomFormatter('%(asctime)s %(levelname)s %(message)s', datefmt='%Y-%m-%dT%H:%M:%S%z')
76
+ fh.setFormatter(formatter)
77
+ eh.setFormatter(formatter)
78
+ ch.setFormatter(formatter)
79
+
80
+ self.addHandler(fh)
81
+ self.addHandler(eh)
82
+ self.addHandler(ch)
83
+
84
+ # Filter console output based on debug_level
85
+ class DebugLevelFilter(logging.Filter):
86
+ def filter(self, record):
87
+ level_map = {
88
+ 0: ['ERROR', 'SUCCESS', 'WARNING', 'INFO', 'DEBUG'],
89
+ 1: ['ERROR'],
90
+ 2: ['SUCCESS'],
91
+ 3: ['WARNING'],
92
+ 4: ['INFO'],
93
+ 5: ['ERROR', 'WARNING'],
94
+ 6: ['INFO', 'SUCCESS'],
95
+ 7: ['ERROR', 'WARNING', 'INFO']
96
+ }
97
+ allowed = level_map.get(int(self.debug_level), [])
98
+ return record.levelname in allowed
99
+
100
+ ch.addFilter(DebugLevelFilter())
101
+
102
+ return self
103
+
104
+ def parse_log(self, log_text):
105
+ ansi_escape = re.compile(r'\x1b\[[0-9;]*m')
106
+ clean = ansi_escape.sub('', log_text)
107
+
108
+ # Match `(username @ folder) 🤌 CL Timing: [timestamp]`
109
+ header_pattern = r"\((.*?) @ (.*?)\) 🤌 CL Timing: \[ (.*?) \]"
110
+ header_match = re.search(header_pattern, clean)
111
+
112
+ if not header_match:
113
+ return None
114
+
115
+ user, module, timestamp = header_match.groups()
116
+ lines = clean.splitlines()
117
+ level_line = lines[1] if len(lines) > 1 else ''
118
+ message = ' '.join(lines[2:]).strip()
119
+
120
+ # Extract level from second line: e.g., "[INFO] Message"
121
+ level_match = re.match(r'\[(\w+)\]', level_line)
122
+ level = level_match.group(1) if level_match else "UNKNOWN"
123
+
124
+ return {
125
+ "user": user,
126
+ "module": module,
127
+ "level": level,
128
+ "timestamp": timestamp,
129
+ "message": ansi_escape.sub('', message)
130
+ }
131
+
132
+
133
+ def jsonifier(self) -> list:
134
+ """
135
+ Reads the log file and returns a list of JSON objects representing each log entry.
136
+ Reserved for central web collection, intentionally not used in CLI.
137
+ Returns:
138
+ list: A list of JSON objects, each representing a log entry.
139
+ """
140
+ log_entries = []
141
+ with open(self.log_file, 'r') as file:
142
+ content = file.read()
143
+ log_lines = content.split('\n\n') # Split by double newlines to separate
144
+ for line in log_lines:
145
+ if line.strip():
146
+ log_entry = self.parse_log(line)
147
+ if log_entry:
148
+ log_entries.append(json.dumps(log_entry))
149
+
150
+ return log_entries
151
+
152
+
153
+ logging.setLoggerClass(ContribLog)
154
+
155
+ # Best initialization example to keep the custom methods available
156
+ logger = ContribLog({ "verbose": '--verbose' in sys.argv, "debug_level": os.getenv('DEBUG_LEVEL', 0) }).get_logger()
@@ -0,0 +1,17 @@
1
+ Metadata-Version: 2.4
2
+ Name: logmachine
3
+ Version: 0.1.0
4
+ Summary: Collaborative, beautiful logging system for distributed developers
5
+ Author-email: Mugabo Gusenga <mugabo@bufferpunk.com>
6
+ Project-URL: Homepage, https://github.com/Scion-Kin/logmachine
7
+ Project-URL: Documentation, https://github.com/Scion-Kin/logmachine#readme
8
+ Project-URL: Source, https://github.com/Scion-Kin/logmachine
9
+ Project-URL: Tracker, https://github.com/Scion-Kin/logmachine/issues
10
+ Keywords: logging,devtools,collaborative,open source,cli,json,ansi
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Operating System :: OS Independent
14
+ Requires-Python: >=3.7
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Dynamic: license-file
@@ -0,0 +1,10 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ logmachine/__init__.py
5
+ logmachine/core.py
6
+ logmachine.egg-info/PKG-INFO
7
+ logmachine.egg-info/SOURCES.txt
8
+ logmachine.egg-info/dependency_links.txt
9
+ logmachine.egg-info/top_level.txt
10
+ tests/test_core.py
@@ -0,0 +1 @@
1
+ logmachine
@@ -0,0 +1,26 @@
1
+ [project]
2
+ name = "logmachine"
3
+ version = "0.1.0"
4
+ description = "Collaborative, beautiful logging system for distributed developers"
5
+ readme = "README.md"
6
+ requires-python = ">=3.7"
7
+ license = { file = "LICENSE" }
8
+ authors = [
9
+ { name="Mugabo Gusenga", email="mugabo@bufferpunk.com" }
10
+ ]
11
+ keywords = ["logging", "devtools", "collaborative", "open source", "cli", "json", "ansi"]
12
+ classifiers = [
13
+ "Programming Language :: Python :: 3",
14
+ "License :: OSI Approved :: MIT License",
15
+ "Operating System :: OS Independent"
16
+ ]
17
+
18
+ [project.urls]
19
+ Homepage = "https://github.com/Scion-Kin/logmachine"
20
+ Documentation = "https://github.com/Scion-Kin/logmachine#readme"
21
+ Source = "https://github.com/Scion-Kin/logmachine"
22
+ Tracker = "https://github.com/Scion-Kin/logmachine/issues"
23
+
24
+ [build-system]
25
+ requires = ["setuptools>=61.0"]
26
+ build-backend = "setuptools.build_meta"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ # tests/test_core.py
2
+ def test_dummy():
3
+ assert True