logmachine 2.0.0__tar.gz → 2.2.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.
- {logmachine-2.0.0 → logmachine-2.2.0}/LICENSE +0 -0
- logmachine-2.2.0/PKG-INFO +195 -0
- logmachine-2.2.0/README.md +177 -0
- logmachine-2.2.0/logmachine/__init__.py +1 -0
- {logmachine-2.0.0 → logmachine-2.2.0}/logmachine/main.py +102 -72
- logmachine-2.2.0/logmachine.egg-info/PKG-INFO +195 -0
- {logmachine-2.0.0 → logmachine-2.2.0}/logmachine.egg-info/SOURCES.txt +0 -0
- {logmachine-2.0.0 → logmachine-2.2.0}/logmachine.egg-info/dependency_links.txt +0 -0
- {logmachine-2.0.0 → logmachine-2.2.0}/logmachine.egg-info/top_level.txt +0 -0
- {logmachine-2.0.0 → logmachine-2.2.0}/pyproject.toml +6 -6
- {logmachine-2.0.0 → logmachine-2.2.0}/tests/test_core.py +0 -0
- logmachine-2.0.0/PKG-INFO +0 -17
- logmachine-2.0.0/README.md +0 -0
- logmachine-2.0.0/logmachine/__init__.py +0 -1
- logmachine-2.0.0/logmachine.egg-info/PKG-INFO +0 -17
- {logmachine-2.0.0 → logmachine-2.2.0}/setup.cfg +0 -0
|
File without changes
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: logmachine
|
|
3
|
+
Version: 2.2.0
|
|
4
|
+
Summary: Collaborative, beautiful logging system for distributed developers
|
|
5
|
+
Author-email: Mugabo Gusenga <mugabo@bufferpunk.com>
|
|
6
|
+
Project-URL: Homepage, https://logmachine.bufferpunk.com
|
|
7
|
+
Project-URL: Documentation, https://github.com/logmachine/python
|
|
8
|
+
Project-URL: Source, https://github.com/logmachine/python
|
|
9
|
+
Project-URL: Tracker, https://github.com/logmachine/python/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
|
|
18
|
+
|
|
19
|
+
# 🧠 LogMachine
|
|
20
|
+
|
|
21
|
+
> Collaborative, beautiful logging system for distributed developers
|
|
22
|
+
|
|
23
|
+
**logmachine** helps teams log smarter. It’s a fully pluggable logging system that supports colored output, JSON parsing, structured log forwarding via **HTTP or Socket.IO**, and log centralization — all from a standard Python logging interface.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 🚀 Features
|
|
28
|
+
|
|
29
|
+
- 🔥 **Color-coded terminal logs** (DEBUG, INFO, WARNING, ERROR, SUCCESS)
|
|
30
|
+
- 📤 **Log forwarding** to a central HTTP or Socket.IO server
|
|
31
|
+
- 🪵 **Custom log levels** (add your own with `.new_level(...)`)
|
|
32
|
+
- 👥 **User identity tracking** for team-based logs
|
|
33
|
+
- 🧩 **Pluggable backends**: send logs to a central server or local files
|
|
34
|
+
- 📦 **Simple JSON output** for web dashboards or collectors
|
|
35
|
+
- 🧽 Strips ANSI escape codes from logs for clean parsing
|
|
36
|
+
- 🧠 Automatically resolves usernames and saves them in `~/.cl_username`
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## ⚙️ Installation
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install logmachine
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## 🧰 Usage
|
|
49
|
+
|
|
50
|
+
### Basic Setup
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
from logmachine import LogMachine
|
|
54
|
+
|
|
55
|
+
# Create a simple logger without central logging
|
|
56
|
+
# Providing a non-empty string initializes the logger with that name, else the root logger is used to collect every single log in the python process.
|
|
57
|
+
logger = LogMachine("myapp", debug_level=1)
|
|
58
|
+
|
|
59
|
+
logger.info("Hello, world!")
|
|
60
|
+
logger.error("An error occurred!")
|
|
61
|
+
logger.success("Operation completed successfully!")
|
|
62
|
+
logger.debug("Debugging information here.")
|
|
63
|
+
logger.warning("This is a warning message.")
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### With Central Logging (HTTP or Socket.IO)
|
|
67
|
+
|
|
68
|
+
You can use the default logger with central logging pointing to "https://logmachine.bufferpunk.com"
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
from logmachine import default_logger
|
|
72
|
+
logger = default_logger()
|
|
73
|
+
logger.info("This log is sent to the LogMachine default central server!")
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
This is the default central logging server for logmachine, and you can create your own room there for free.
|
|
77
|
+
To use your own central logging server, provide the configuration as shown below:
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
logger_config = {
|
|
81
|
+
"url": "https://logmachine.bufferpunk.com", # Base server URL
|
|
82
|
+
"room": "team_alpha", # Your organization or room
|
|
83
|
+
"endpoint": "/api/logs", # Optional, defaults to /api/logs
|
|
84
|
+
"headers": {"Authorization": "Bearer token"},
|
|
85
|
+
"socketio": True, # Set False to use HTTP
|
|
86
|
+
"socketio_path": "/api/socket.io/" # Optional
|
|
87
|
+
}
|
|
88
|
+
logger = LogMachine("with_central", debug_level=0, central=logger_config, socketio=True)
|
|
89
|
+
logger.success("Central logging is working!")
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## 🎨 Log Format
|
|
95
|
+
|
|
96
|
+
Every log includes:
|
|
97
|
+
|
|
98
|
+
* ✅ Username (resolved automatically or via server)
|
|
99
|
+
* 📁 Module directory
|
|
100
|
+
* ⏱️ Timestamp
|
|
101
|
+
* 📦 Level (INFO, ERROR, etc.)
|
|
102
|
+
* 📝 Message
|
|
103
|
+
|
|
104
|
+
Sample (terminal):
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
(username @ myapp) 🤌 CL Timing: [ 2025-08-04T11:23:52 ]
|
|
108
|
+
[ INFO ] Server started on port 8000
|
|
109
|
+
🏁
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## 🛠️ Advanced
|
|
115
|
+
|
|
116
|
+
### Add Your Own Log Level
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
logger.new_level("CRITICAL_HACK", 60)
|
|
120
|
+
logger.new_level("CRITICAL_HACK", 60, color="\033[38;5;13m") # Optional color... does your girlfriend love pink? Maybe you should be in a relationship with your terminal.
|
|
121
|
+
logger.critical_hack("Zero day found!")
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## 📤 Parse & Export
|
|
127
|
+
|
|
128
|
+
### Convert Logs to JSON
|
|
129
|
+
|
|
130
|
+
This is useful for sending logs to web dashboards or log collectors that expect JSON.
|
|
131
|
+
It reads the your log files, parses the log entries, and outputs them as JSON objects.
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
json_logs = log.jsonifier()
|
|
135
|
+
for entry in json_logs:
|
|
136
|
+
print(entry)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## 📡 Central Server Compatibility
|
|
142
|
+
|
|
143
|
+
To use Socket.IO, your central server must support these events:
|
|
144
|
+
|
|
145
|
+
* `log`: Receives log payloads: `{ room: string, data: object }`
|
|
146
|
+
* `GET /api/get_username?base=localname`: Returns `{ "username": "..." }`
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## 🤖 Environment Variables
|
|
151
|
+
|
|
152
|
+
* `CL_USERNAME`: Manually override detected username
|
|
153
|
+
* Automatically stored in `~/.cl_username` for persistent identity
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## 🔐 Security
|
|
158
|
+
|
|
159
|
+
* HTTP headers (e.g. `Authorization`) can be injected
|
|
160
|
+
* Central log transmission is fully customizable
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## 🔧 Configuration Summary
|
|
165
|
+
|
|
166
|
+
| Param | Type | Description |
|
|
167
|
+
| --------------- | ------ | -------------------------------------------------- |
|
|
168
|
+
| `url` | `str` | Central server base URL |
|
|
169
|
+
| `room` | `str` | Logical group or org name |
|
|
170
|
+
| `endpoint` | `str` | HTTP endpoint for POST logs (default: `/api/logs`) |
|
|
171
|
+
| `headers` | `dict` | Extra headers to send (e.g. auth token) |
|
|
172
|
+
| `socketio` | `bool` | Whether to use Socket.IO instead of HTTP |
|
|
173
|
+
| `socketio_path` | `str` | Path to socket.io on the server |
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## 📄 License
|
|
178
|
+
|
|
179
|
+
MIT License
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## 🙋♂️ Author
|
|
184
|
+
|
|
185
|
+
Mugabo Gusenga
|
|
186
|
+
[logmachine.bufferpunk.com](https://logmachine.bufferpunk.com)
|
|
187
|
+
[GitHub](https://github.com/Scion-Kin/logmachine)
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## ❤️ Contribute
|
|
192
|
+
|
|
193
|
+
PRs and issues are welcome!
|
|
194
|
+
This tool is built for devs who want **beautiful logs with distributed brains**.
|
|
195
|
+
Let’s make debugging fun again.
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# 🧠 LogMachine
|
|
2
|
+
|
|
3
|
+
> Collaborative, beautiful logging system for distributed developers
|
|
4
|
+
|
|
5
|
+
**logmachine** helps teams log smarter. It’s a fully pluggable logging system that supports colored output, JSON parsing, structured log forwarding via **HTTP or Socket.IO**, and log centralization — all from a standard Python logging interface.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 🚀 Features
|
|
10
|
+
|
|
11
|
+
- 🔥 **Color-coded terminal logs** (DEBUG, INFO, WARNING, ERROR, SUCCESS)
|
|
12
|
+
- 📤 **Log forwarding** to a central HTTP or Socket.IO server
|
|
13
|
+
- 🪵 **Custom log levels** (add your own with `.new_level(...)`)
|
|
14
|
+
- 👥 **User identity tracking** for team-based logs
|
|
15
|
+
- 🧩 **Pluggable backends**: send logs to a central server or local files
|
|
16
|
+
- 📦 **Simple JSON output** for web dashboards or collectors
|
|
17
|
+
- 🧽 Strips ANSI escape codes from logs for clean parsing
|
|
18
|
+
- 🧠 Automatically resolves usernames and saves them in `~/.cl_username`
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## ⚙️ Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install logmachine
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 🧰 Usage
|
|
31
|
+
|
|
32
|
+
### Basic Setup
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
from logmachine import LogMachine
|
|
36
|
+
|
|
37
|
+
# Create a simple logger without central logging
|
|
38
|
+
# Providing a non-empty string initializes the logger with that name, else the root logger is used to collect every single log in the python process.
|
|
39
|
+
logger = LogMachine("myapp", debug_level=1)
|
|
40
|
+
|
|
41
|
+
logger.info("Hello, world!")
|
|
42
|
+
logger.error("An error occurred!")
|
|
43
|
+
logger.success("Operation completed successfully!")
|
|
44
|
+
logger.debug("Debugging information here.")
|
|
45
|
+
logger.warning("This is a warning message.")
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### With Central Logging (HTTP or Socket.IO)
|
|
49
|
+
|
|
50
|
+
You can use the default logger with central logging pointing to "https://logmachine.bufferpunk.com"
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
from logmachine import default_logger
|
|
54
|
+
logger = default_logger()
|
|
55
|
+
logger.info("This log is sent to the LogMachine default central server!")
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
This is the default central logging server for logmachine, and you can create your own room there for free.
|
|
59
|
+
To use your own central logging server, provide the configuration as shown below:
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
logger_config = {
|
|
63
|
+
"url": "https://logmachine.bufferpunk.com", # Base server URL
|
|
64
|
+
"room": "team_alpha", # Your organization or room
|
|
65
|
+
"endpoint": "/api/logs", # Optional, defaults to /api/logs
|
|
66
|
+
"headers": {"Authorization": "Bearer token"},
|
|
67
|
+
"socketio": True, # Set False to use HTTP
|
|
68
|
+
"socketio_path": "/api/socket.io/" # Optional
|
|
69
|
+
}
|
|
70
|
+
logger = LogMachine("with_central", debug_level=0, central=logger_config, socketio=True)
|
|
71
|
+
logger.success("Central logging is working!")
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## 🎨 Log Format
|
|
77
|
+
|
|
78
|
+
Every log includes:
|
|
79
|
+
|
|
80
|
+
* ✅ Username (resolved automatically or via server)
|
|
81
|
+
* 📁 Module directory
|
|
82
|
+
* ⏱️ Timestamp
|
|
83
|
+
* 📦 Level (INFO, ERROR, etc.)
|
|
84
|
+
* 📝 Message
|
|
85
|
+
|
|
86
|
+
Sample (terminal):
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
(username @ myapp) 🤌 CL Timing: [ 2025-08-04T11:23:52 ]
|
|
90
|
+
[ INFO ] Server started on port 8000
|
|
91
|
+
🏁
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 🛠️ Advanced
|
|
97
|
+
|
|
98
|
+
### Add Your Own Log Level
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
logger.new_level("CRITICAL_HACK", 60)
|
|
102
|
+
logger.new_level("CRITICAL_HACK", 60, color="\033[38;5;13m") # Optional color... does your girlfriend love pink? Maybe you should be in a relationship with your terminal.
|
|
103
|
+
logger.critical_hack("Zero day found!")
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## 📤 Parse & Export
|
|
109
|
+
|
|
110
|
+
### Convert Logs to JSON
|
|
111
|
+
|
|
112
|
+
This is useful for sending logs to web dashboards or log collectors that expect JSON.
|
|
113
|
+
It reads the your log files, parses the log entries, and outputs them as JSON objects.
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
json_logs = log.jsonifier()
|
|
117
|
+
for entry in json_logs:
|
|
118
|
+
print(entry)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## 📡 Central Server Compatibility
|
|
124
|
+
|
|
125
|
+
To use Socket.IO, your central server must support these events:
|
|
126
|
+
|
|
127
|
+
* `log`: Receives log payloads: `{ room: string, data: object }`
|
|
128
|
+
* `GET /api/get_username?base=localname`: Returns `{ "username": "..." }`
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## 🤖 Environment Variables
|
|
133
|
+
|
|
134
|
+
* `CL_USERNAME`: Manually override detected username
|
|
135
|
+
* Automatically stored in `~/.cl_username` for persistent identity
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## 🔐 Security
|
|
140
|
+
|
|
141
|
+
* HTTP headers (e.g. `Authorization`) can be injected
|
|
142
|
+
* Central log transmission is fully customizable
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## 🔧 Configuration Summary
|
|
147
|
+
|
|
148
|
+
| Param | Type | Description |
|
|
149
|
+
| --------------- | ------ | -------------------------------------------------- |
|
|
150
|
+
| `url` | `str` | Central server base URL |
|
|
151
|
+
| `room` | `str` | Logical group or org name |
|
|
152
|
+
| `endpoint` | `str` | HTTP endpoint for POST logs (default: `/api/logs`) |
|
|
153
|
+
| `headers` | `dict` | Extra headers to send (e.g. auth token) |
|
|
154
|
+
| `socketio` | `bool` | Whether to use Socket.IO instead of HTTP |
|
|
155
|
+
| `socketio_path` | `str` | Path to socket.io on the server |
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## 📄 License
|
|
160
|
+
|
|
161
|
+
MIT License
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## 🙋♂️ Author
|
|
166
|
+
|
|
167
|
+
Mugabo Gusenga
|
|
168
|
+
[logmachine.bufferpunk.com](https://logmachine.bufferpunk.com)
|
|
169
|
+
[GitHub](https://github.com/Scion-Kin/logmachine)
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## ❤️ Contribute
|
|
174
|
+
|
|
175
|
+
PRs and issues are welcome!
|
|
176
|
+
This tool is built for devs who want **beautiful logs with distributed brains**.
|
|
177
|
+
Let’s make debugging fun again.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .main import LogMachine, default_logger
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
import atexit
|
|
1
2
|
import os
|
|
2
3
|
import re
|
|
3
4
|
import json
|
|
4
5
|
import logging
|
|
5
6
|
import requests
|
|
6
7
|
import socketio
|
|
8
|
+
import queue
|
|
9
|
+
from logging.handlers import QueueHandler, QueueListener
|
|
10
|
+
|
|
7
11
|
|
|
8
12
|
def get_login():
|
|
9
13
|
"""
|
|
@@ -11,12 +15,17 @@ def get_login():
|
|
|
11
15
|
:return: The login name of the current user.
|
|
12
16
|
"""
|
|
13
17
|
try:
|
|
14
|
-
|
|
18
|
+
if not os.path.exists(os.path.expanduser("~/.cl_username")):
|
|
19
|
+
return os.getlogin()
|
|
20
|
+
else:
|
|
21
|
+
with open(os.path.expanduser("~/.cl_username"), 'r') as f:
|
|
22
|
+
os.environ['CL_USERNAME'] = f.read().strip()
|
|
23
|
+
return os.environ['CL_USERNAME']
|
|
15
24
|
except Exception:
|
|
16
25
|
return os.environ.get('USER', 'unknown')
|
|
17
26
|
|
|
18
27
|
|
|
19
|
-
class
|
|
28
|
+
class HTTPTransporter(logging.StreamHandler):
|
|
20
29
|
"""
|
|
21
30
|
A class to handle the transport of log messages using HTTP requests.
|
|
22
31
|
This class sends log messages to a central server via HTTP POST requests.
|
|
@@ -36,22 +45,19 @@ class RequestsTransporter(logging.StreamHandler):
|
|
|
36
45
|
try:
|
|
37
46
|
msg = self.format(record)
|
|
38
47
|
super().emit(record)
|
|
39
|
-
if self.central:
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
)
|
|
53
|
-
if response.status_code != 200:
|
|
54
|
-
raise Exception(f"Failed to send log to central: {response.text}")
|
|
48
|
+
if not self.central or not self.central.get('room'):
|
|
49
|
+
raise ValueError("""Central configuration must include 'room' for log transport.
|
|
50
|
+
Example: {'url': 'http://central-server/api/logs', 'room': 'my_organization_name'}""")
|
|
51
|
+
|
|
52
|
+
log_data = self.parse_log(msg)
|
|
53
|
+
if log_data:
|
|
54
|
+
response = requests.post(
|
|
55
|
+
f"{self.central.get('url', '') + self.central.get('endpoint', '/api/logs')}?room={self.central.get('room', '')}",
|
|
56
|
+
json=log_data,
|
|
57
|
+
headers={"Content-Type": "application/json", **self.central.get('headers', {})}
|
|
58
|
+
)
|
|
59
|
+
if response.status_code != 200:
|
|
60
|
+
raise Exception(f"Failed to send log to central: {response.text}")
|
|
55
61
|
|
|
56
62
|
except Exception:
|
|
57
63
|
self.handleError(record)
|
|
@@ -68,7 +74,7 @@ class SocketIOTransporter(logging.StreamHandler):
|
|
|
68
74
|
self.central = kwargs.get('central', None)
|
|
69
75
|
self.sio = socketio.Client()
|
|
70
76
|
if self.central:
|
|
71
|
-
self.sio.connect(self.central.get('url', ''), headers=self.central.get('headers', {}), socketio_path=self.central.get('socketio_path', '/api/socket.io'))
|
|
77
|
+
self.sio.connect(self.central.get('url', ''), headers=self.central.get('headers', {}), socketio_path=self.central.get('socketio_path', '/api/socket.io/'))
|
|
72
78
|
|
|
73
79
|
def emit(self, record):
|
|
74
80
|
try:
|
|
@@ -90,57 +96,67 @@ class SocketIOTransporter(logging.StreamHandler):
|
|
|
90
96
|
|
|
91
97
|
|
|
92
98
|
class CustomFormatter(logging.Formatter):
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
99
|
+
def __init__(self, *args, **kwargs):
|
|
100
|
+
super().__init__(*args, **kwargs)
|
|
101
|
+
self.colors = {
|
|
102
|
+
'DEBUG': '\x1b[36m',
|
|
103
|
+
'INFO': '\x1b[34m',
|
|
104
|
+
'WARNING': '\x1b[33m',
|
|
105
|
+
'ERROR': '\x1b[31m',
|
|
106
|
+
'SUCCESS': '\x1b[32m'
|
|
107
|
+
}
|
|
108
|
+
self.reset = '\x1b[0m'
|
|
109
|
+
self.bold = '\x1b[1m'
|
|
110
|
+
self.level_formats = {
|
|
111
|
+
'DEBUG': self.bold + '[ DEBUG ]' + self.reset,
|
|
112
|
+
'INFO': self.bold + '[ INFO ]' + self.reset,
|
|
113
|
+
'WARNING': self.bold + '[ WARNING ]' + self.reset,
|
|
114
|
+
'ERROR': self.bold + '[ ERROR ]' + self.reset,
|
|
115
|
+
'SUCCESS': self.bold + '[ SUCCESS ]' + self.reset
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
def set_color(self, levelname: str, color_code: str):
|
|
119
|
+
"""
|
|
120
|
+
Set a custom color for a specific log level.
|
|
121
|
+
:param levelname: The name of the log level (e.g., 'DEBUG', 'INFO').
|
|
122
|
+
:param color_code: The ANSI color code to use for the specified log level.
|
|
123
|
+
"""
|
|
124
|
+
self.colors[levelname] = color_code
|
|
125
|
+
self.level_formats[levelname] = f"{self.bold}[ {levelname} ]{self.reset}"
|
|
109
126
|
|
|
110
127
|
def format(self, record) -> str:
|
|
111
128
|
username = os.environ.get('CL_USERNAME') or get_login()
|
|
112
129
|
|
|
113
130
|
levelname = record.levelname
|
|
114
|
-
color = self.
|
|
115
|
-
level_fmt = self.
|
|
116
|
-
level_fmt = f"{color}{level_fmt}{self.
|
|
131
|
+
color = self.colors.get(levelname, '')
|
|
132
|
+
level_fmt = self.level_formats.get(levelname, f'{levelname}')
|
|
133
|
+
level_fmt = f"{color}{level_fmt}{self.reset}"
|
|
117
134
|
record.asctime = self.formatTime(record, self.datefmt)
|
|
118
135
|
module_file = record.pathname
|
|
119
136
|
parent_dir = os.path.basename(os.path.dirname(record.pathname)) if module_file != '<stdin>' else 'stdin'
|
|
120
137
|
|
|
121
|
-
return f"""{self.
|
|
138
|
+
return f"""{self.colors.get('DEBUG')}({username}{self.reset} @ {self.colors.get('WARNING') + parent_dir + self.reset}) 🤌 CL Timing: {color}[ {record.asctime} ]{self.reset}
|
|
122
139
|
{level_fmt} {record.getMessage()}
|
|
123
140
|
🏁"""
|
|
124
141
|
|
|
125
|
-
class
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
super().__init__(*args, level=logging.DEBUG)
|
|
130
|
-
logging.addLevelName(self.SUCCESS, "SUCCESS")
|
|
142
|
+
class LogMachine(logging.Logger):
|
|
143
|
+
def __init__(self, name="", *args, **kwargs) -> None:
|
|
144
|
+
super().__init__(name, *args, level=int(kwargs.get('debug_level', 0)))
|
|
145
|
+
logging.addLevelName(25, "SUCCESS")
|
|
131
146
|
self.log_file = kwargs.get('log_file', 'logs.log')
|
|
132
147
|
self.error_file = kwargs.get('error_file', 'errors.log')
|
|
133
148
|
self.debug_level = int(kwargs.get('debug_level', 0))
|
|
134
149
|
self.verbose = kwargs.get('verbose', False)
|
|
135
150
|
self.central = kwargs.get('central', None)
|
|
136
|
-
self.
|
|
151
|
+
self.queue = queue.Queue()
|
|
137
152
|
|
|
138
153
|
# Remove existing handlers
|
|
139
|
-
self.handlers
|
|
154
|
+
for h in self.handlers[:]:
|
|
155
|
+
self.removeHandler(h)
|
|
140
156
|
|
|
141
157
|
# File handlers
|
|
142
158
|
fh = logging.FileHandler(self.log_file)
|
|
143
|
-
fh.setLevel(
|
|
159
|
+
fh.setLevel(self.debug_level)
|
|
144
160
|
eh = logging.FileHandler(self.error_file)
|
|
145
161
|
eh.setLevel(logging.ERROR)
|
|
146
162
|
|
|
@@ -148,7 +164,7 @@ class ContribLog(logging.Logger):
|
|
|
148
164
|
if self.central:
|
|
149
165
|
"""
|
|
150
166
|
The central uses usernames to group logs.
|
|
151
|
-
OS usernames are used to identify the
|
|
167
|
+
OS usernames are used to identify the user, meaning names can clash.
|
|
152
168
|
Therefore, we avoid a user having to define a username, rather, ask the central server to provide it.
|
|
153
169
|
After getting the username, we store it in the user's home directory in a file named `.cl_username`.
|
|
154
170
|
This way, the user can change it at any time, and it will be used in all future logs without needing to request it again.
|
|
@@ -158,42 +174,37 @@ class ContribLog(logging.Logger):
|
|
|
158
174
|
login = get_login()
|
|
159
175
|
response = requests.get(f"{self.central.get('url', '')}/api/get_username?base={login}")
|
|
160
176
|
if response.status_code == 200:
|
|
161
|
-
os.environ['CL_USERNAME'] = response.json().get('username'
|
|
177
|
+
os.environ['CL_USERNAME'] = response.json().get('username') or 'unknown' # Unknown will probably never be reached, but it's a fallback.
|
|
162
178
|
if os.environ.get('CL_USERNAME') != 'unknown':
|
|
163
179
|
with open(os.path.expanduser("~/.cl_username"), 'w') as f:
|
|
164
180
|
f.write(os.environ['CL_USERNAME'])
|
|
165
181
|
else:
|
|
166
182
|
os.environ['CL_USERNAME'] = 'unknown'
|
|
167
|
-
except Exception
|
|
183
|
+
except Exception:
|
|
168
184
|
os.environ['CL_USERNAME'] = 'unknown'
|
|
169
185
|
else:
|
|
170
|
-
|
|
171
|
-
os.environ['CL_USERNAME'] = f.read().strip()
|
|
186
|
+
get_login()
|
|
172
187
|
|
|
173
|
-
if not kwargs.get('attached', False):
|
|
174
|
-
ch =
|
|
188
|
+
if not kwargs.get('attached', False) and not self.central.get('socketio', False):
|
|
189
|
+
ch = HTTPTransporter(log_parser=self.parse_log, central=self.central)
|
|
175
190
|
else:
|
|
176
191
|
ch = SocketIOTransporter(log_parser=self.parse_log, central=self.central)
|
|
177
|
-
|
|
178
192
|
else:
|
|
179
193
|
ch = logging.StreamHandler()
|
|
180
194
|
|
|
181
195
|
ch.setLevel(logging.DEBUG)
|
|
182
196
|
|
|
183
|
-
formatter = CustomFormatter('%(asctime)s %(levelname)s %(message)s', datefmt='%Y-%m-%dT%H:%M:%S%z')
|
|
184
|
-
fh.setFormatter(formatter)
|
|
185
|
-
eh.setFormatter(formatter)
|
|
186
|
-
ch.setFormatter(formatter)
|
|
187
|
-
|
|
188
|
-
self.addHandler(fh)
|
|
189
|
-
self.addHandler(eh)
|
|
190
|
-
self.addHandler(ch)
|
|
197
|
+
self.formatter = CustomFormatter('%(asctime)s %(levelname)s %(message)s', datefmt='%Y-%m-%dT%H:%M:%S%z')
|
|
198
|
+
fh.setFormatter(self.formatter)
|
|
199
|
+
eh.setFormatter(self.formatter)
|
|
200
|
+
ch.setFormatter(self.formatter)
|
|
201
|
+
self.addHandler(QueueHandler(self.queue))
|
|
191
202
|
|
|
192
203
|
# Filter console output based on debug_level
|
|
193
204
|
class DebugLevelFilter(logging.Filter):
|
|
194
205
|
def __init__(self, debug_level):
|
|
195
206
|
super().__init__()
|
|
196
|
-
self.debug_level =
|
|
207
|
+
self.debug_level = debug_level
|
|
197
208
|
|
|
198
209
|
def filter(self, record):
|
|
199
210
|
if self.debug_level == 0:
|
|
@@ -212,12 +223,22 @@ class ContribLog(logging.Logger):
|
|
|
212
223
|
return record.levelname in allowed
|
|
213
224
|
|
|
214
225
|
ch.addFilter(DebugLevelFilter(self.debug_level if not self.verbose else 0))
|
|
226
|
+
self.listener = QueueListener(self.queue, fh, eh, ch)
|
|
227
|
+
self.listener.start()
|
|
228
|
+
atexit.register(self.listener.stop)
|
|
229
|
+
self.info("LogMachine initialized with debug level {} with{}".format(
|
|
230
|
+
self.debug_level,
|
|
231
|
+
self.central and
|
|
232
|
+
f" central logging to {self.central.get('url', '')}" or
|
|
233
|
+
"out central logging"
|
|
234
|
+
)
|
|
235
|
+
)
|
|
215
236
|
|
|
216
237
|
def success(self, msg, *args, **kwargs) -> None:
|
|
217
|
-
if self.isEnabledFor(
|
|
218
|
-
self._log(
|
|
238
|
+
if self.isEnabledFor(25):
|
|
239
|
+
self._log(25, msg, args, stacklevel=2, **kwargs)
|
|
219
240
|
|
|
220
|
-
def new_level(self, level_name: str, level_num: int):
|
|
241
|
+
def new_level(self, level_name: str, level_num: int, ansi_color="\x1b[37m") -> None:
|
|
221
242
|
"""
|
|
222
243
|
Dynamically add a new logging level.
|
|
223
244
|
:param level_name: Name of the new logging level.
|
|
@@ -228,8 +249,9 @@ class ContribLog(logging.Logger):
|
|
|
228
249
|
logging.addLevelName(level_num, level_name)
|
|
229
250
|
setattr(self, level_name.lower(), lambda msg, *args, **kwargs: self._log(level_num, msg, args, stacklevel=2, **kwargs))
|
|
230
251
|
self.setLevel(min(self.level, level_num)) # Ensure the logger's level is set appropriately
|
|
252
|
+
self.formatter.set_color(level_name, ansi_color) # Add color formatting for the new level
|
|
231
253
|
|
|
232
|
-
def parse_log(self, log_text) -> dict:
|
|
254
|
+
def parse_log(self, log_text) -> dict | None:
|
|
233
255
|
log_text = log_text.strip()
|
|
234
256
|
ansi_escape = re.compile(r'\x1b\[[0-9;]*m')
|
|
235
257
|
end_escape = re.compile(r'🏁')
|
|
@@ -240,7 +262,7 @@ class ContribLog(logging.Logger):
|
|
|
240
262
|
header_match = re.search(header_pattern, clean)
|
|
241
263
|
|
|
242
264
|
if not header_match:
|
|
243
|
-
return
|
|
265
|
+
return
|
|
244
266
|
|
|
245
267
|
user, module, timestamp = header_match.groups()
|
|
246
268
|
lines = clean.splitlines()
|
|
@@ -257,7 +279,7 @@ class ContribLog(logging.Logger):
|
|
|
257
279
|
"timestamp": timestamp,
|
|
258
280
|
"message": end_escape.sub('', message).strip()
|
|
259
281
|
}
|
|
260
|
-
|
|
282
|
+
|
|
261
283
|
def jsonifier(self) -> list:
|
|
262
284
|
"""
|
|
263
285
|
Reads the log file and returns a list of JSON objects representing each log entry.
|
|
@@ -278,4 +300,12 @@ class ContribLog(logging.Logger):
|
|
|
278
300
|
return log_entries
|
|
279
301
|
|
|
280
302
|
|
|
281
|
-
|
|
303
|
+
def default_logger():
|
|
304
|
+
return LogMachine('default_logger', debug_level=0, verbose=False, central={
|
|
305
|
+
'url': 'https://logmachine.bufferpunk.com',
|
|
306
|
+
'room': f'{get_login()}_logs',
|
|
307
|
+
'headers': {}
|
|
308
|
+
})
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
logging.setLoggerClass(LogMachine)
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: logmachine
|
|
3
|
+
Version: 2.2.0
|
|
4
|
+
Summary: Collaborative, beautiful logging system for distributed developers
|
|
5
|
+
Author-email: Mugabo Gusenga <mugabo@bufferpunk.com>
|
|
6
|
+
Project-URL: Homepage, https://logmachine.bufferpunk.com
|
|
7
|
+
Project-URL: Documentation, https://github.com/logmachine/python
|
|
8
|
+
Project-URL: Source, https://github.com/logmachine/python
|
|
9
|
+
Project-URL: Tracker, https://github.com/logmachine/python/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
|
|
18
|
+
|
|
19
|
+
# 🧠 LogMachine
|
|
20
|
+
|
|
21
|
+
> Collaborative, beautiful logging system for distributed developers
|
|
22
|
+
|
|
23
|
+
**logmachine** helps teams log smarter. It’s a fully pluggable logging system that supports colored output, JSON parsing, structured log forwarding via **HTTP or Socket.IO**, and log centralization — all from a standard Python logging interface.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 🚀 Features
|
|
28
|
+
|
|
29
|
+
- 🔥 **Color-coded terminal logs** (DEBUG, INFO, WARNING, ERROR, SUCCESS)
|
|
30
|
+
- 📤 **Log forwarding** to a central HTTP or Socket.IO server
|
|
31
|
+
- 🪵 **Custom log levels** (add your own with `.new_level(...)`)
|
|
32
|
+
- 👥 **User identity tracking** for team-based logs
|
|
33
|
+
- 🧩 **Pluggable backends**: send logs to a central server or local files
|
|
34
|
+
- 📦 **Simple JSON output** for web dashboards or collectors
|
|
35
|
+
- 🧽 Strips ANSI escape codes from logs for clean parsing
|
|
36
|
+
- 🧠 Automatically resolves usernames and saves them in `~/.cl_username`
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## ⚙️ Installation
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install logmachine
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## 🧰 Usage
|
|
49
|
+
|
|
50
|
+
### Basic Setup
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
from logmachine import LogMachine
|
|
54
|
+
|
|
55
|
+
# Create a simple logger without central logging
|
|
56
|
+
# Providing a non-empty string initializes the logger with that name, else the root logger is used to collect every single log in the python process.
|
|
57
|
+
logger = LogMachine("myapp", debug_level=1)
|
|
58
|
+
|
|
59
|
+
logger.info("Hello, world!")
|
|
60
|
+
logger.error("An error occurred!")
|
|
61
|
+
logger.success("Operation completed successfully!")
|
|
62
|
+
logger.debug("Debugging information here.")
|
|
63
|
+
logger.warning("This is a warning message.")
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### With Central Logging (HTTP or Socket.IO)
|
|
67
|
+
|
|
68
|
+
You can use the default logger with central logging pointing to "https://logmachine.bufferpunk.com"
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
from logmachine import default_logger
|
|
72
|
+
logger = default_logger()
|
|
73
|
+
logger.info("This log is sent to the LogMachine default central server!")
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
This is the default central logging server for logmachine, and you can create your own room there for free.
|
|
77
|
+
To use your own central logging server, provide the configuration as shown below:
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
logger_config = {
|
|
81
|
+
"url": "https://logmachine.bufferpunk.com", # Base server URL
|
|
82
|
+
"room": "team_alpha", # Your organization or room
|
|
83
|
+
"endpoint": "/api/logs", # Optional, defaults to /api/logs
|
|
84
|
+
"headers": {"Authorization": "Bearer token"},
|
|
85
|
+
"socketio": True, # Set False to use HTTP
|
|
86
|
+
"socketio_path": "/api/socket.io/" # Optional
|
|
87
|
+
}
|
|
88
|
+
logger = LogMachine("with_central", debug_level=0, central=logger_config, socketio=True)
|
|
89
|
+
logger.success("Central logging is working!")
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## 🎨 Log Format
|
|
95
|
+
|
|
96
|
+
Every log includes:
|
|
97
|
+
|
|
98
|
+
* ✅ Username (resolved automatically or via server)
|
|
99
|
+
* 📁 Module directory
|
|
100
|
+
* ⏱️ Timestamp
|
|
101
|
+
* 📦 Level (INFO, ERROR, etc.)
|
|
102
|
+
* 📝 Message
|
|
103
|
+
|
|
104
|
+
Sample (terminal):
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
(username @ myapp) 🤌 CL Timing: [ 2025-08-04T11:23:52 ]
|
|
108
|
+
[ INFO ] Server started on port 8000
|
|
109
|
+
🏁
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## 🛠️ Advanced
|
|
115
|
+
|
|
116
|
+
### Add Your Own Log Level
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
logger.new_level("CRITICAL_HACK", 60)
|
|
120
|
+
logger.new_level("CRITICAL_HACK", 60, color="\033[38;5;13m") # Optional color... does your girlfriend love pink? Maybe you should be in a relationship with your terminal.
|
|
121
|
+
logger.critical_hack("Zero day found!")
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## 📤 Parse & Export
|
|
127
|
+
|
|
128
|
+
### Convert Logs to JSON
|
|
129
|
+
|
|
130
|
+
This is useful for sending logs to web dashboards or log collectors that expect JSON.
|
|
131
|
+
It reads the your log files, parses the log entries, and outputs them as JSON objects.
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
json_logs = log.jsonifier()
|
|
135
|
+
for entry in json_logs:
|
|
136
|
+
print(entry)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## 📡 Central Server Compatibility
|
|
142
|
+
|
|
143
|
+
To use Socket.IO, your central server must support these events:
|
|
144
|
+
|
|
145
|
+
* `log`: Receives log payloads: `{ room: string, data: object }`
|
|
146
|
+
* `GET /api/get_username?base=localname`: Returns `{ "username": "..." }`
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## 🤖 Environment Variables
|
|
151
|
+
|
|
152
|
+
* `CL_USERNAME`: Manually override detected username
|
|
153
|
+
* Automatically stored in `~/.cl_username` for persistent identity
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## 🔐 Security
|
|
158
|
+
|
|
159
|
+
* HTTP headers (e.g. `Authorization`) can be injected
|
|
160
|
+
* Central log transmission is fully customizable
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## 🔧 Configuration Summary
|
|
165
|
+
|
|
166
|
+
| Param | Type | Description |
|
|
167
|
+
| --------------- | ------ | -------------------------------------------------- |
|
|
168
|
+
| `url` | `str` | Central server base URL |
|
|
169
|
+
| `room` | `str` | Logical group or org name |
|
|
170
|
+
| `endpoint` | `str` | HTTP endpoint for POST logs (default: `/api/logs`) |
|
|
171
|
+
| `headers` | `dict` | Extra headers to send (e.g. auth token) |
|
|
172
|
+
| `socketio` | `bool` | Whether to use Socket.IO instead of HTTP |
|
|
173
|
+
| `socketio_path` | `str` | Path to socket.io on the server |
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## 📄 License
|
|
178
|
+
|
|
179
|
+
MIT License
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## 🙋♂️ Author
|
|
184
|
+
|
|
185
|
+
Mugabo Gusenga
|
|
186
|
+
[logmachine.bufferpunk.com](https://logmachine.bufferpunk.com)
|
|
187
|
+
[GitHub](https://github.com/Scion-Kin/logmachine)
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## ❤️ Contribute
|
|
192
|
+
|
|
193
|
+
PRs and issues are welcome!
|
|
194
|
+
This tool is built for devs who want **beautiful logs with distributed brains**.
|
|
195
|
+
Let’s make debugging fun again.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "logmachine"
|
|
3
|
-
version = "2.
|
|
3
|
+
version = "2.2.0"
|
|
4
4
|
description = "Collaborative, beautiful logging system for distributed developers"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.7"
|
|
@@ -16,11 +16,11 @@ classifiers = [
|
|
|
16
16
|
]
|
|
17
17
|
|
|
18
18
|
[project.urls]
|
|
19
|
-
Homepage = "https://
|
|
20
|
-
Documentation = "https://github.com/
|
|
21
|
-
Source = "https://github.com/
|
|
22
|
-
Tracker = "https://github.com/
|
|
19
|
+
Homepage = "https://logmachine.bufferpunk.com"
|
|
20
|
+
Documentation = "https://github.com/logmachine/python"
|
|
21
|
+
Source = "https://github.com/logmachine/python"
|
|
22
|
+
Tracker = "https://github.com/logmachine/python/issues"
|
|
23
23
|
|
|
24
24
|
[build-system]
|
|
25
|
-
requires = ["setuptools>=61.0"]
|
|
25
|
+
requires = ["setuptools>=61.0", "websocket-client", "python-socketio", "requests"]
|
|
26
26
|
build-backend = "setuptools.build_meta"
|
|
File without changes
|
logmachine-2.0.0/PKG-INFO
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: logmachine
|
|
3
|
-
Version: 2.0.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
|
logmachine-2.0.0/README.md
DELETED
|
File without changes
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
from .main import ContribLog
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: logmachine
|
|
3
|
-
Version: 2.0.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
|