spanlogger 1.0.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.
- spanlogger-1.0.0/LICENSE +21 -0
- spanlogger-1.0.0/PKG-INFO +189 -0
- spanlogger-1.0.0/README.md +162 -0
- spanlogger-1.0.0/pyproject.toml +37 -0
- spanlogger-1.0.0/setup.cfg +4 -0
- spanlogger-1.0.0/spanlogger/__init__.py +5 -0
- spanlogger-1.0.0/spanlogger/logger.py +335 -0
- spanlogger-1.0.0/spanlogger.egg-info/PKG-INFO +189 -0
- spanlogger-1.0.0/spanlogger.egg-info/SOURCES.txt +9 -0
- spanlogger-1.0.0/spanlogger.egg-info/dependency_links.txt +1 -0
- spanlogger-1.0.0/spanlogger.egg-info/top_level.txt +1 -0
spanlogger-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 rowsvips
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: spanlogger
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Professional colored terminal logger with timestamps, symbols, and title bar support.
|
|
5
|
+
Author: rowsvips
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://vmshops.mysellauth.com
|
|
8
|
+
Keywords: logger,terminal,colored,console,logging,ansi,cli
|
|
9
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Classifier: Topic :: System :: Logging
|
|
23
|
+
Requires-Python: >=3.8
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
|
|
28
|
+
# spanlogger
|
|
29
|
+
|
|
30
|
+
Professional colored terminal logger for Python by **rowsvips**.
|
|
31
|
+
|
|
32
|
+
Zero dependencies. Thread-safe. Windows & Linux compatible.
|
|
33
|
+
|
|
34
|
+
## Install
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install spanlogger
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Quick Start
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from spanlogger import Logger, Colors
|
|
44
|
+
|
|
45
|
+
log = Logger(title="MyApp", show_time=True)
|
|
46
|
+
|
|
47
|
+
log.info("Application started")
|
|
48
|
+
log.success("Connected to server")
|
|
49
|
+
log.warning("Rate limit approaching")
|
|
50
|
+
log.error("Connection failed")
|
|
51
|
+
log.money("Payment received [$50.00]")
|
|
52
|
+
log.debug("Internal state: ok")
|
|
53
|
+
log.captcha("Captcha detected on session_abc****")
|
|
54
|
+
log.custom("Special event", symbol="★", color=Colors.BRIGHT_YELLOW)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Output
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
07:23 AM [¥] Application started
|
|
61
|
+
07:23 AM [+] Connected to server
|
|
62
|
+
07:23 AM [!] Rate limit approaching
|
|
63
|
+
07:23 AM [-] Connection failed
|
|
64
|
+
07:23 AM [$] Payment received [$50.00]
|
|
65
|
+
07:23 AM [~] Internal state: ok
|
|
66
|
+
07:23 AM [¥] Captcha detected on session_abc****
|
|
67
|
+
07:23 AM [★] Special event
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Title Bar
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
log.print_title_bar(
|
|
74
|
+
"MyApp v1.0",
|
|
75
|
+
"@rowsvips",
|
|
76
|
+
"vmshops.mysellauth.com",
|
|
77
|
+
stats={"Success": 10, "Failed": 2}
|
|
78
|
+
)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
────────────────────────────────────────────────────────────────────────────────
|
|
83
|
+
MyApp v1.0 | @rowsvips | vmshops.mysellauth.com | Success: 10 - Failed: 2
|
|
84
|
+
────────────────────────────────────────────────────────────────────────────────
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Console Window Title
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
log.set_title("MyApp v1.0", "@rowsvips")
|
|
91
|
+
log.set_title_stats(Success=10, Failed=2, Captcha=5)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Counter System
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
log.increment("success")
|
|
98
|
+
log.increment("failed", 3)
|
|
99
|
+
|
|
100
|
+
print(log.get_count("success"))
|
|
101
|
+
print(log.get_all_counts())
|
|
102
|
+
|
|
103
|
+
log.reset_counts()
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Contextual Helpers
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
log.redeemed("code_abc****", "session_123****", "[AT: 2.5s | Type: Premium]")
|
|
110
|
+
log.failed("Process Task", "Error: session expired")
|
|
111
|
+
log.added("Account", "user_xyz****", "session_123****")
|
|
112
|
+
log.removed("Session", "session_old****")
|
|
113
|
+
log.thread_sleep(5, "Before retry")
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Custom Symbols & Colors
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
log.custom("Diamond", symbol="♦", color=Colors.BRIGHT_MAGENTA)
|
|
120
|
+
log.custom("Heart", symbol="♥", color=Colors.BRIGHT_RED)
|
|
121
|
+
log.custom("Arrow", symbol="→", color=Colors.BRIGHT_CYAN)
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Inline Colored Text
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
token = Logger.colorize("session_abc****", Colors.BRIGHT_CYAN)
|
|
128
|
+
log.info(f"Processing on {token}")
|
|
129
|
+
|
|
130
|
+
log.info(f"Status: {Logger.bold('ACTIVE')}")
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Utilities
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
log.separator()
|
|
137
|
+
log.separator(char="=", length=40, color=Colors.CYAN)
|
|
138
|
+
|
|
139
|
+
log.blank()
|
|
140
|
+
log.clear()
|
|
141
|
+
|
|
142
|
+
log.banner("All Done!", color=Colors.BRIGHT_GREEN, width=50)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Options
|
|
146
|
+
|
|
147
|
+
| Parameter | Default | Description |
|
|
148
|
+
|---|---|---|
|
|
149
|
+
| `title` | `"Application"` | Application title |
|
|
150
|
+
| `show_time` | `True` | Show timestamps |
|
|
151
|
+
| `time_format` | `"%I:%M %p"` | Time format (12h AM/PM) |
|
|
152
|
+
| `title_separator` | `" \| "` | Separator for title parts |
|
|
153
|
+
| `title_color` | `Colors.CYAN` | Title bar color |
|
|
154
|
+
| `time_color` | `Colors.BRIGHT_BLACK` | Timestamp color |
|
|
155
|
+
| `bracket_style` | `"square"` | Bracket style: square, round, angle, curly |
|
|
156
|
+
| `log_file` | `None` | Optional file path to save logs |
|
|
157
|
+
|
|
158
|
+
## Log File
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
log = Logger(log_file="app.log")
|
|
162
|
+
log.info("This goes to terminal AND file")
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Log Levels
|
|
166
|
+
|
|
167
|
+
| Method | Symbol | Color |
|
|
168
|
+
|---|---|---|
|
|
169
|
+
| `info()` | `[¥]` | Cyan |
|
|
170
|
+
| `success()` | `[+]` | Green |
|
|
171
|
+
| `warning()` | `[!]` | Yellow |
|
|
172
|
+
| `error()` | `[-]` | Red |
|
|
173
|
+
| `money()` | `[$]` | Bright Green |
|
|
174
|
+
| `input_log()` | `[>]` | Magenta |
|
|
175
|
+
| `debug()` | `[~]` | Gray |
|
|
176
|
+
| `captcha()` | `[¥]` | Yellow |
|
|
177
|
+
| `custom()` | Custom | Custom |
|
|
178
|
+
|
|
179
|
+
## Default Instance
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
from spanlogger import log
|
|
183
|
+
|
|
184
|
+
log.info("Quick access without creating an instance")
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## License
|
|
188
|
+
|
|
189
|
+
MIT - by rowsvips | vmshops.mysellauth.com
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# spanlogger
|
|
2
|
+
|
|
3
|
+
Professional colored terminal logger for Python by **rowsvips**.
|
|
4
|
+
|
|
5
|
+
Zero dependencies. Thread-safe. Windows & Linux compatible.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install spanlogger
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
from spanlogger import Logger, Colors
|
|
17
|
+
|
|
18
|
+
log = Logger(title="MyApp", show_time=True)
|
|
19
|
+
|
|
20
|
+
log.info("Application started")
|
|
21
|
+
log.success("Connected to server")
|
|
22
|
+
log.warning("Rate limit approaching")
|
|
23
|
+
log.error("Connection failed")
|
|
24
|
+
log.money("Payment received [$50.00]")
|
|
25
|
+
log.debug("Internal state: ok")
|
|
26
|
+
log.captcha("Captcha detected on session_abc****")
|
|
27
|
+
log.custom("Special event", symbol="★", color=Colors.BRIGHT_YELLOW)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Output
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
07:23 AM [¥] Application started
|
|
34
|
+
07:23 AM [+] Connected to server
|
|
35
|
+
07:23 AM [!] Rate limit approaching
|
|
36
|
+
07:23 AM [-] Connection failed
|
|
37
|
+
07:23 AM [$] Payment received [$50.00]
|
|
38
|
+
07:23 AM [~] Internal state: ok
|
|
39
|
+
07:23 AM [¥] Captcha detected on session_abc****
|
|
40
|
+
07:23 AM [★] Special event
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Title Bar
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
log.print_title_bar(
|
|
47
|
+
"MyApp v1.0",
|
|
48
|
+
"@rowsvips",
|
|
49
|
+
"vmshops.mysellauth.com",
|
|
50
|
+
stats={"Success": 10, "Failed": 2}
|
|
51
|
+
)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
────────────────────────────────────────────────────────────────────────────────
|
|
56
|
+
MyApp v1.0 | @rowsvips | vmshops.mysellauth.com | Success: 10 - Failed: 2
|
|
57
|
+
────────────────────────────────────────────────────────────────────────────────
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Console Window Title
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
log.set_title("MyApp v1.0", "@rowsvips")
|
|
64
|
+
log.set_title_stats(Success=10, Failed=2, Captcha=5)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Counter System
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
log.increment("success")
|
|
71
|
+
log.increment("failed", 3)
|
|
72
|
+
|
|
73
|
+
print(log.get_count("success"))
|
|
74
|
+
print(log.get_all_counts())
|
|
75
|
+
|
|
76
|
+
log.reset_counts()
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Contextual Helpers
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
log.redeemed("code_abc****", "session_123****", "[AT: 2.5s | Type: Premium]")
|
|
83
|
+
log.failed("Process Task", "Error: session expired")
|
|
84
|
+
log.added("Account", "user_xyz****", "session_123****")
|
|
85
|
+
log.removed("Session", "session_old****")
|
|
86
|
+
log.thread_sleep(5, "Before retry")
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Custom Symbols & Colors
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
log.custom("Diamond", symbol="♦", color=Colors.BRIGHT_MAGENTA)
|
|
93
|
+
log.custom("Heart", symbol="♥", color=Colors.BRIGHT_RED)
|
|
94
|
+
log.custom("Arrow", symbol="→", color=Colors.BRIGHT_CYAN)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Inline Colored Text
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
token = Logger.colorize("session_abc****", Colors.BRIGHT_CYAN)
|
|
101
|
+
log.info(f"Processing on {token}")
|
|
102
|
+
|
|
103
|
+
log.info(f"Status: {Logger.bold('ACTIVE')}")
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Utilities
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
log.separator()
|
|
110
|
+
log.separator(char="=", length=40, color=Colors.CYAN)
|
|
111
|
+
|
|
112
|
+
log.blank()
|
|
113
|
+
log.clear()
|
|
114
|
+
|
|
115
|
+
log.banner("All Done!", color=Colors.BRIGHT_GREEN, width=50)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Options
|
|
119
|
+
|
|
120
|
+
| Parameter | Default | Description |
|
|
121
|
+
|---|---|---|
|
|
122
|
+
| `title` | `"Application"` | Application title |
|
|
123
|
+
| `show_time` | `True` | Show timestamps |
|
|
124
|
+
| `time_format` | `"%I:%M %p"` | Time format (12h AM/PM) |
|
|
125
|
+
| `title_separator` | `" \| "` | Separator for title parts |
|
|
126
|
+
| `title_color` | `Colors.CYAN` | Title bar color |
|
|
127
|
+
| `time_color` | `Colors.BRIGHT_BLACK` | Timestamp color |
|
|
128
|
+
| `bracket_style` | `"square"` | Bracket style: square, round, angle, curly |
|
|
129
|
+
| `log_file` | `None` | Optional file path to save logs |
|
|
130
|
+
|
|
131
|
+
## Log File
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
log = Logger(log_file="app.log")
|
|
135
|
+
log.info("This goes to terminal AND file")
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Log Levels
|
|
139
|
+
|
|
140
|
+
| Method | Symbol | Color |
|
|
141
|
+
|---|---|---|
|
|
142
|
+
| `info()` | `[¥]` | Cyan |
|
|
143
|
+
| `success()` | `[+]` | Green |
|
|
144
|
+
| `warning()` | `[!]` | Yellow |
|
|
145
|
+
| `error()` | `[-]` | Red |
|
|
146
|
+
| `money()` | `[$]` | Bright Green |
|
|
147
|
+
| `input_log()` | `[>]` | Magenta |
|
|
148
|
+
| `debug()` | `[~]` | Gray |
|
|
149
|
+
| `captcha()` | `[¥]` | Yellow |
|
|
150
|
+
| `custom()` | Custom | Custom |
|
|
151
|
+
|
|
152
|
+
## Default Instance
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
from spanlogger import log
|
|
156
|
+
|
|
157
|
+
log.info("Quick access without creating an instance")
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## License
|
|
161
|
+
|
|
162
|
+
MIT - by rowsvips | vmshops.mysellauth.com
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "spanlogger"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Professional colored terminal logger with timestamps, symbols, and title bar support."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = {text = "MIT"}
|
|
11
|
+
requires-python = ">=3.8"
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "rowsvips"}
|
|
14
|
+
]
|
|
15
|
+
keywords = ["logger", "terminal", "colored", "console", "logging", "ansi", "cli"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 5 - Production/Stable",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Operating System :: OS Independent",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3.8",
|
|
23
|
+
"Programming Language :: Python :: 3.9",
|
|
24
|
+
"Programming Language :: Python :: 3.10",
|
|
25
|
+
"Programming Language :: Python :: 3.11",
|
|
26
|
+
"Programming Language :: Python :: 3.12",
|
|
27
|
+
"Programming Language :: Python :: 3.13",
|
|
28
|
+
"Programming Language :: Python :: 3.14",
|
|
29
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
30
|
+
"Topic :: System :: Logging",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[project.urls]
|
|
34
|
+
Homepage = "https://vmshops.mysellauth.com"
|
|
35
|
+
|
|
36
|
+
[tool.setuptools.packages.find]
|
|
37
|
+
include = ["spanlogger*"]
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
import io
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
import threading
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from enum import Enum
|
|
7
|
+
from typing import Optional
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Colors:
|
|
11
|
+
RESET = "\033[0m"
|
|
12
|
+
BOLD = "\033[1m"
|
|
13
|
+
DIM = "\033[2m"
|
|
14
|
+
UNDERLINE = "\033[4m"
|
|
15
|
+
|
|
16
|
+
BLACK = "\033[30m"
|
|
17
|
+
RED = "\033[31m"
|
|
18
|
+
GREEN = "\033[32m"
|
|
19
|
+
YELLOW = "\033[33m"
|
|
20
|
+
BLUE = "\033[34m"
|
|
21
|
+
MAGENTA = "\033[35m"
|
|
22
|
+
CYAN = "\033[36m"
|
|
23
|
+
WHITE = "\033[37m"
|
|
24
|
+
|
|
25
|
+
BRIGHT_BLACK = "\033[90m"
|
|
26
|
+
BRIGHT_RED = "\033[91m"
|
|
27
|
+
BRIGHT_GREEN = "\033[92m"
|
|
28
|
+
BRIGHT_YELLOW = "\033[93m"
|
|
29
|
+
BRIGHT_BLUE = "\033[94m"
|
|
30
|
+
BRIGHT_MAGENTA = "\033[95m"
|
|
31
|
+
BRIGHT_CYAN = "\033[96m"
|
|
32
|
+
BRIGHT_WHITE = "\033[97m"
|
|
33
|
+
|
|
34
|
+
BG_BLACK = "\033[40m"
|
|
35
|
+
BG_RED = "\033[41m"
|
|
36
|
+
BG_GREEN = "\033[42m"
|
|
37
|
+
BG_YELLOW = "\033[43m"
|
|
38
|
+
BG_BLUE = "\033[44m"
|
|
39
|
+
BG_MAGENTA = "\033[45m"
|
|
40
|
+
BG_CYAN = "\033[46m"
|
|
41
|
+
BG_WHITE = "\033[47m"
|
|
42
|
+
|
|
43
|
+
BG_BRIGHT_BLACK = "\033[100m"
|
|
44
|
+
BG_BRIGHT_RED = "\033[101m"
|
|
45
|
+
BG_BRIGHT_GREEN = "\033[102m"
|
|
46
|
+
BG_BRIGHT_YELLOW = "\033[103m"
|
|
47
|
+
BG_BRIGHT_BLUE = "\033[104m"
|
|
48
|
+
BG_BRIGHT_MAGENTA = "\033[105m"
|
|
49
|
+
BG_BRIGHT_CYAN = "\033[106m"
|
|
50
|
+
BG_BRIGHT_WHITE = "\033[107m"
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class LogLevel(Enum):
|
|
54
|
+
INFO = ("¥", Colors.CYAN, Colors.BRIGHT_CYAN)
|
|
55
|
+
SUCCESS = ("+", Colors.GREEN, Colors.BRIGHT_GREEN)
|
|
56
|
+
WARNING = ("!", Colors.YELLOW, Colors.BRIGHT_YELLOW)
|
|
57
|
+
ERROR = ("-", Colors.RED, Colors.BRIGHT_RED)
|
|
58
|
+
MONEY = ("$", Colors.BRIGHT_GREEN, Colors.BRIGHT_GREEN)
|
|
59
|
+
INPUT = (">", Colors.MAGENTA, Colors.BRIGHT_MAGENTA)
|
|
60
|
+
DEBUG = ("~", Colors.BRIGHT_BLACK, Colors.BRIGHT_BLACK)
|
|
61
|
+
CAPTCHA = ("¥", Colors.YELLOW, Colors.BRIGHT_YELLOW)
|
|
62
|
+
CUSTOM = ("*", Colors.BRIGHT_WHITE, Colors.BRIGHT_WHITE)
|
|
63
|
+
|
|
64
|
+
def __init__(self, symbol: str, bracket_color: str, message_color: str):
|
|
65
|
+
self.symbol = symbol
|
|
66
|
+
self.bracket_color = bracket_color
|
|
67
|
+
self.message_color = message_color
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class Logger:
|
|
71
|
+
_lock = threading.Lock()
|
|
72
|
+
|
|
73
|
+
def __init__(
|
|
74
|
+
self,
|
|
75
|
+
title: str = "Application",
|
|
76
|
+
show_time: bool = True,
|
|
77
|
+
time_format: str = "%I:%M %p",
|
|
78
|
+
title_separator: str = " | ",
|
|
79
|
+
title_color: str = Colors.CYAN,
|
|
80
|
+
time_color: str = Colors.BRIGHT_BLACK,
|
|
81
|
+
bracket_style: str = "square",
|
|
82
|
+
log_file: Optional[str] = None,
|
|
83
|
+
):
|
|
84
|
+
self.title = title
|
|
85
|
+
self.show_time = show_time
|
|
86
|
+
self.time_format = time_format
|
|
87
|
+
self.title_separator = title_separator
|
|
88
|
+
self.title_color = title_color
|
|
89
|
+
self.time_color = time_color
|
|
90
|
+
self.bracket_style = bracket_style
|
|
91
|
+
self.log_file = log_file
|
|
92
|
+
self._counters: dict[str, int] = {}
|
|
93
|
+
self._title_stats: dict[str, str] = {}
|
|
94
|
+
self._title_parts: list[str] = []
|
|
95
|
+
|
|
96
|
+
if os.name == "nt":
|
|
97
|
+
self._enable_windows_ansi()
|
|
98
|
+
|
|
99
|
+
self._brackets = {
|
|
100
|
+
"square": ("[", "]"),
|
|
101
|
+
"round": ("(", ")"),
|
|
102
|
+
"angle": ("<", ">"),
|
|
103
|
+
"curly": ("{", "}"),
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
@staticmethod
|
|
107
|
+
def _enable_windows_ansi():
|
|
108
|
+
try:
|
|
109
|
+
import ctypes
|
|
110
|
+
kernel32 = ctypes.windll.kernel32
|
|
111
|
+
kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7)
|
|
112
|
+
except Exception:
|
|
113
|
+
pass
|
|
114
|
+
|
|
115
|
+
try:
|
|
116
|
+
if sys.stdout.encoding and sys.stdout.encoding.lower() != "utf-8":
|
|
117
|
+
sys.stdout = io.TextIOWrapper(
|
|
118
|
+
sys.stdout.buffer, encoding="utf-8", errors="replace", line_buffering=True
|
|
119
|
+
)
|
|
120
|
+
if sys.stderr.encoding and sys.stderr.encoding.lower() != "utf-8":
|
|
121
|
+
sys.stderr = io.TextIOWrapper(
|
|
122
|
+
sys.stderr.buffer, encoding="utf-8", errors="replace", line_buffering=True
|
|
123
|
+
)
|
|
124
|
+
except Exception:
|
|
125
|
+
pass
|
|
126
|
+
|
|
127
|
+
def _get_brackets(self) -> tuple[str, str]:
|
|
128
|
+
return self._brackets.get(self.bracket_style, ("[", "]"))
|
|
129
|
+
|
|
130
|
+
def _get_timestamp(self) -> str:
|
|
131
|
+
if not self.show_time:
|
|
132
|
+
return ""
|
|
133
|
+
now = datetime.now().strftime(self.time_format)
|
|
134
|
+
return f"{self.time_color}{now}{Colors.RESET}"
|
|
135
|
+
|
|
136
|
+
def _format_message(self, level: LogLevel, message: str, extra_color: Optional[str] = None) -> str:
|
|
137
|
+
lb, rb = self._get_brackets()
|
|
138
|
+
color = extra_color or level.message_color
|
|
139
|
+
|
|
140
|
+
time_str = self._get_timestamp()
|
|
141
|
+
time_part = f"{time_str} " if time_str else ""
|
|
142
|
+
|
|
143
|
+
symbol_part = (
|
|
144
|
+
f"{level.bracket_color}{lb}"
|
|
145
|
+
f"{Colors.BOLD}{level.message_color}{level.symbol}"
|
|
146
|
+
f"{Colors.RESET}{level.bracket_color}{rb}{Colors.RESET}"
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
msg_part = f"{color}{message}{Colors.RESET}"
|
|
150
|
+
|
|
151
|
+
return f"{time_part}{symbol_part} {msg_part}"
|
|
152
|
+
|
|
153
|
+
def _write(self, formatted: str, raw_message: str = ""):
|
|
154
|
+
with self._lock:
|
|
155
|
+
sys.stdout.write(formatted + "\n")
|
|
156
|
+
sys.stdout.flush()
|
|
157
|
+
|
|
158
|
+
if self.log_file and raw_message:
|
|
159
|
+
try:
|
|
160
|
+
with open(self.log_file, "a", encoding="utf-8") as f:
|
|
161
|
+
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
162
|
+
f.write(f"[{timestamp}] {raw_message}\n")
|
|
163
|
+
except Exception:
|
|
164
|
+
pass
|
|
165
|
+
|
|
166
|
+
def info(self, message: str):
|
|
167
|
+
formatted = self._format_message(LogLevel.INFO, message)
|
|
168
|
+
self._write(formatted, f"[INFO] {message}")
|
|
169
|
+
|
|
170
|
+
def success(self, message: str):
|
|
171
|
+
formatted = self._format_message(LogLevel.SUCCESS, message)
|
|
172
|
+
self._write(formatted, f"[SUCCESS] {message}")
|
|
173
|
+
|
|
174
|
+
def warning(self, message: str):
|
|
175
|
+
formatted = self._format_message(LogLevel.WARNING, message)
|
|
176
|
+
self._write(formatted, f"[WARNING] {message}")
|
|
177
|
+
|
|
178
|
+
def error(self, message: str):
|
|
179
|
+
formatted = self._format_message(LogLevel.ERROR, message)
|
|
180
|
+
self._write(formatted, f"[ERROR] {message}")
|
|
181
|
+
|
|
182
|
+
def money(self, message: str):
|
|
183
|
+
formatted = self._format_message(LogLevel.MONEY, message)
|
|
184
|
+
self._write(formatted, f"[MONEY] {message}")
|
|
185
|
+
|
|
186
|
+
def input_log(self, message: str):
|
|
187
|
+
formatted = self._format_message(LogLevel.INPUT, message)
|
|
188
|
+
self._write(formatted, f"[INPUT] {message}")
|
|
189
|
+
|
|
190
|
+
def debug(self, message: str):
|
|
191
|
+
formatted = self._format_message(LogLevel.DEBUG, message)
|
|
192
|
+
self._write(formatted, f"[DEBUG] {message}")
|
|
193
|
+
|
|
194
|
+
def captcha(self, message: str):
|
|
195
|
+
formatted = self._format_message(LogLevel.CAPTCHA, message)
|
|
196
|
+
self._write(formatted, f"[CAPTCHA] {message}")
|
|
197
|
+
|
|
198
|
+
def custom(self, message: str, symbol: str = "*", color: str = Colors.BRIGHT_WHITE):
|
|
199
|
+
lb, rb = self._get_brackets()
|
|
200
|
+
time_str = self._get_timestamp()
|
|
201
|
+
time_part = f"{time_str} " if time_str else ""
|
|
202
|
+
|
|
203
|
+
symbol_part = (
|
|
204
|
+
f"{color}{lb}"
|
|
205
|
+
f"{Colors.BOLD}{color}{symbol}"
|
|
206
|
+
f"{Colors.RESET}{color}{rb}{Colors.RESET}"
|
|
207
|
+
)
|
|
208
|
+
msg_part = f"{color}{message}{Colors.RESET}"
|
|
209
|
+
formatted = f"{time_part}{symbol_part} {msg_part}"
|
|
210
|
+
self._write(formatted, f"[CUSTOM] {message}")
|
|
211
|
+
|
|
212
|
+
def set_title(self, *parts: str):
|
|
213
|
+
self._title_parts = list(parts)
|
|
214
|
+
self._refresh_title()
|
|
215
|
+
|
|
216
|
+
def set_title_stats(self, **stats: any):
|
|
217
|
+
for key, value in stats.items():
|
|
218
|
+
self._title_stats[key] = str(value)
|
|
219
|
+
self._refresh_title()
|
|
220
|
+
|
|
221
|
+
def _refresh_title(self):
|
|
222
|
+
parts = list(self._title_parts)
|
|
223
|
+
|
|
224
|
+
if self._title_stats:
|
|
225
|
+
stats_str = " - ".join(
|
|
226
|
+
f"{k}: {v}" for k, v in self._title_stats.items()
|
|
227
|
+
)
|
|
228
|
+
parts.append(stats_str)
|
|
229
|
+
|
|
230
|
+
full_title = self.title_separator.join(parts)
|
|
231
|
+
|
|
232
|
+
sys.stdout.write(f"\033]0;{full_title}\007")
|
|
233
|
+
sys.stdout.flush()
|
|
234
|
+
|
|
235
|
+
def print_title_bar(self, *parts: str, stats: Optional[dict] = None):
|
|
236
|
+
all_parts = list(parts)
|
|
237
|
+
|
|
238
|
+
if stats:
|
|
239
|
+
stats_parts = []
|
|
240
|
+
for k, v in stats.items():
|
|
241
|
+
stats_parts.append(f"{k}: {v}")
|
|
242
|
+
stats_str = " - ".join(stats_parts)
|
|
243
|
+
all_parts.append(stats_str)
|
|
244
|
+
|
|
245
|
+
separator = f"{Colors.BRIGHT_BLACK}{self.title_separator}{Colors.RESET}"
|
|
246
|
+
colored_parts = [f"{self.title_color}{p}{Colors.RESET}" for p in all_parts]
|
|
247
|
+
bar = separator.join(colored_parts)
|
|
248
|
+
|
|
249
|
+
with self._lock:
|
|
250
|
+
sys.stdout.write(f"{Colors.BRIGHT_BLACK}{'─' * 80}{Colors.RESET}\n")
|
|
251
|
+
sys.stdout.write(f" {bar}\n")
|
|
252
|
+
sys.stdout.write(f"{Colors.BRIGHT_BLACK}{'─' * 80}{Colors.RESET}\n")
|
|
253
|
+
sys.stdout.flush()
|
|
254
|
+
|
|
255
|
+
def increment(self, key: str, amount: int = 1) -> int:
|
|
256
|
+
with self._lock:
|
|
257
|
+
self._counters[key] = self._counters.get(key, 0) + amount
|
|
258
|
+
return self._counters[key]
|
|
259
|
+
|
|
260
|
+
def get_count(self, key: str) -> int:
|
|
261
|
+
return self._counters.get(key, 0)
|
|
262
|
+
|
|
263
|
+
def get_all_counts(self) -> dict[str, int]:
|
|
264
|
+
return dict(self._counters)
|
|
265
|
+
|
|
266
|
+
def reset_counts(self):
|
|
267
|
+
with self._lock:
|
|
268
|
+
self._counters.clear()
|
|
269
|
+
|
|
270
|
+
def separator(self, char: str = "─", length: int = 60, color: str = Colors.BRIGHT_BLACK):
|
|
271
|
+
line = f"{color}{char * length}{Colors.RESET}"
|
|
272
|
+
self._write(line)
|
|
273
|
+
|
|
274
|
+
def blank(self):
|
|
275
|
+
self._write("")
|
|
276
|
+
|
|
277
|
+
def banner(self, text: str, color: str = Colors.CYAN, width: int = 60):
|
|
278
|
+
border = f"{color}{'═' * width}{Colors.RESET}"
|
|
279
|
+
padded = text.center(width)
|
|
280
|
+
banner_text = f"{color}{padded}{Colors.RESET}"
|
|
281
|
+
with self._lock:
|
|
282
|
+
sys.stdout.write(f"{border}\n{banner_text}\n{border}\n")
|
|
283
|
+
sys.stdout.flush()
|
|
284
|
+
|
|
285
|
+
def clear(self):
|
|
286
|
+
os.system("cls" if os.name == "nt" else "clear")
|
|
287
|
+
|
|
288
|
+
@staticmethod
|
|
289
|
+
def colorize(text: str, color: str) -> str:
|
|
290
|
+
return f"{color}{text}{Colors.RESET}"
|
|
291
|
+
|
|
292
|
+
@staticmethod
|
|
293
|
+
def bold(text: str) -> str:
|
|
294
|
+
return f"{Colors.BOLD}{text}{Colors.RESET}"
|
|
295
|
+
|
|
296
|
+
@staticmethod
|
|
297
|
+
def dim(text: str) -> str:
|
|
298
|
+
return f"{Colors.DIM}{text}{Colors.RESET}"
|
|
299
|
+
|
|
300
|
+
def redeemed(self, promo: str, token: str, details: str = ""):
|
|
301
|
+
msg = f"Redeemed {Colors.BRIGHT_GREEN}{promo}{Colors.RESET}"
|
|
302
|
+
msg += f" {Colors.CYAN}On{Colors.RESET} {Colors.BRIGHT_CYAN}{token}{Colors.RESET}"
|
|
303
|
+
if details:
|
|
304
|
+
msg += f" {Colors.BRIGHT_BLACK}{details}{Colors.RESET}"
|
|
305
|
+
formatted = self._format_message(LogLevel.MONEY, msg)
|
|
306
|
+
self._write(formatted, f"[REDEEMED] {promo} on {token} {details}")
|
|
307
|
+
|
|
308
|
+
def failed(self, action: str, reason: str = ""):
|
|
309
|
+
msg = f"Failed to {Colors.BRIGHT_RED}{action}{Colors.RESET}"
|
|
310
|
+
if reason:
|
|
311
|
+
msg += f", {Colors.YELLOW}{reason}{Colors.RESET}"
|
|
312
|
+
formatted = self._format_message(LogLevel.ERROR, msg)
|
|
313
|
+
self._write(formatted, f"[FAILED] {action} - {reason}")
|
|
314
|
+
|
|
315
|
+
def added(self, item_type: str, item: str, target: str = ""):
|
|
316
|
+
msg = f"Added {Colors.BRIGHT_GREEN}{item_type}{Colors.RESET} {Colors.GREEN}{item}{Colors.RESET}"
|
|
317
|
+
if target:
|
|
318
|
+
msg += f" {Colors.CYAN}To{Colors.RESET} {Colors.BRIGHT_CYAN}{target}{Colors.RESET}"
|
|
319
|
+
formatted = self._format_message(LogLevel.SUCCESS, msg)
|
|
320
|
+
self._write(formatted, f"[ADDED] {item_type} {item} to {target}")
|
|
321
|
+
|
|
322
|
+
def removed(self, item_type: str, item: str):
|
|
323
|
+
msg = f"Removed {Colors.YELLOW}{item_type}{Colors.RESET}: {Colors.BRIGHT_YELLOW}{item}{Colors.RESET}"
|
|
324
|
+
formatted = self._format_message(LogLevel.WARNING, msg)
|
|
325
|
+
self._write(formatted, f"[REMOVED] {item_type} {item}")
|
|
326
|
+
|
|
327
|
+
def thread_sleep(self, seconds: int, reason: str = ""):
|
|
328
|
+
msg = f"Thread Sleeping for {Colors.BRIGHT_CYAN}{seconds}s{Colors.RESET}"
|
|
329
|
+
if reason:
|
|
330
|
+
msg += f" {Colors.BRIGHT_BLACK}{reason}{Colors.RESET}"
|
|
331
|
+
formatted = self._format_message(LogLevel.INPUT, msg)
|
|
332
|
+
self._write(formatted, f"[SLEEP] {seconds}s {reason}")
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
log = Logger()
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: spanlogger
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Professional colored terminal logger with timestamps, symbols, and title bar support.
|
|
5
|
+
Author: rowsvips
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://vmshops.mysellauth.com
|
|
8
|
+
Keywords: logger,terminal,colored,console,logging,ansi,cli
|
|
9
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Classifier: Topic :: System :: Logging
|
|
23
|
+
Requires-Python: >=3.8
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
|
|
28
|
+
# spanlogger
|
|
29
|
+
|
|
30
|
+
Professional colored terminal logger for Python by **rowsvips**.
|
|
31
|
+
|
|
32
|
+
Zero dependencies. Thread-safe. Windows & Linux compatible.
|
|
33
|
+
|
|
34
|
+
## Install
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install spanlogger
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Quick Start
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from spanlogger import Logger, Colors
|
|
44
|
+
|
|
45
|
+
log = Logger(title="MyApp", show_time=True)
|
|
46
|
+
|
|
47
|
+
log.info("Application started")
|
|
48
|
+
log.success("Connected to server")
|
|
49
|
+
log.warning("Rate limit approaching")
|
|
50
|
+
log.error("Connection failed")
|
|
51
|
+
log.money("Payment received [$50.00]")
|
|
52
|
+
log.debug("Internal state: ok")
|
|
53
|
+
log.captcha("Captcha detected on session_abc****")
|
|
54
|
+
log.custom("Special event", symbol="★", color=Colors.BRIGHT_YELLOW)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Output
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
07:23 AM [¥] Application started
|
|
61
|
+
07:23 AM [+] Connected to server
|
|
62
|
+
07:23 AM [!] Rate limit approaching
|
|
63
|
+
07:23 AM [-] Connection failed
|
|
64
|
+
07:23 AM [$] Payment received [$50.00]
|
|
65
|
+
07:23 AM [~] Internal state: ok
|
|
66
|
+
07:23 AM [¥] Captcha detected on session_abc****
|
|
67
|
+
07:23 AM [★] Special event
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Title Bar
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
log.print_title_bar(
|
|
74
|
+
"MyApp v1.0",
|
|
75
|
+
"@rowsvips",
|
|
76
|
+
"vmshops.mysellauth.com",
|
|
77
|
+
stats={"Success": 10, "Failed": 2}
|
|
78
|
+
)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
────────────────────────────────────────────────────────────────────────────────
|
|
83
|
+
MyApp v1.0 | @rowsvips | vmshops.mysellauth.com | Success: 10 - Failed: 2
|
|
84
|
+
────────────────────────────────────────────────────────────────────────────────
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Console Window Title
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
log.set_title("MyApp v1.0", "@rowsvips")
|
|
91
|
+
log.set_title_stats(Success=10, Failed=2, Captcha=5)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Counter System
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
log.increment("success")
|
|
98
|
+
log.increment("failed", 3)
|
|
99
|
+
|
|
100
|
+
print(log.get_count("success"))
|
|
101
|
+
print(log.get_all_counts())
|
|
102
|
+
|
|
103
|
+
log.reset_counts()
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Contextual Helpers
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
log.redeemed("code_abc****", "session_123****", "[AT: 2.5s | Type: Premium]")
|
|
110
|
+
log.failed("Process Task", "Error: session expired")
|
|
111
|
+
log.added("Account", "user_xyz****", "session_123****")
|
|
112
|
+
log.removed("Session", "session_old****")
|
|
113
|
+
log.thread_sleep(5, "Before retry")
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Custom Symbols & Colors
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
log.custom("Diamond", symbol="♦", color=Colors.BRIGHT_MAGENTA)
|
|
120
|
+
log.custom("Heart", symbol="♥", color=Colors.BRIGHT_RED)
|
|
121
|
+
log.custom("Arrow", symbol="→", color=Colors.BRIGHT_CYAN)
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Inline Colored Text
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
token = Logger.colorize("session_abc****", Colors.BRIGHT_CYAN)
|
|
128
|
+
log.info(f"Processing on {token}")
|
|
129
|
+
|
|
130
|
+
log.info(f"Status: {Logger.bold('ACTIVE')}")
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Utilities
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
log.separator()
|
|
137
|
+
log.separator(char="=", length=40, color=Colors.CYAN)
|
|
138
|
+
|
|
139
|
+
log.blank()
|
|
140
|
+
log.clear()
|
|
141
|
+
|
|
142
|
+
log.banner("All Done!", color=Colors.BRIGHT_GREEN, width=50)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Options
|
|
146
|
+
|
|
147
|
+
| Parameter | Default | Description |
|
|
148
|
+
|---|---|---|
|
|
149
|
+
| `title` | `"Application"` | Application title |
|
|
150
|
+
| `show_time` | `True` | Show timestamps |
|
|
151
|
+
| `time_format` | `"%I:%M %p"` | Time format (12h AM/PM) |
|
|
152
|
+
| `title_separator` | `" \| "` | Separator for title parts |
|
|
153
|
+
| `title_color` | `Colors.CYAN` | Title bar color |
|
|
154
|
+
| `time_color` | `Colors.BRIGHT_BLACK` | Timestamp color |
|
|
155
|
+
| `bracket_style` | `"square"` | Bracket style: square, round, angle, curly |
|
|
156
|
+
| `log_file` | `None` | Optional file path to save logs |
|
|
157
|
+
|
|
158
|
+
## Log File
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
log = Logger(log_file="app.log")
|
|
162
|
+
log.info("This goes to terminal AND file")
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Log Levels
|
|
166
|
+
|
|
167
|
+
| Method | Symbol | Color |
|
|
168
|
+
|---|---|---|
|
|
169
|
+
| `info()` | `[¥]` | Cyan |
|
|
170
|
+
| `success()` | `[+]` | Green |
|
|
171
|
+
| `warning()` | `[!]` | Yellow |
|
|
172
|
+
| `error()` | `[-]` | Red |
|
|
173
|
+
| `money()` | `[$]` | Bright Green |
|
|
174
|
+
| `input_log()` | `[>]` | Magenta |
|
|
175
|
+
| `debug()` | `[~]` | Gray |
|
|
176
|
+
| `captcha()` | `[¥]` | Yellow |
|
|
177
|
+
| `custom()` | Custom | Custom |
|
|
178
|
+
|
|
179
|
+
## Default Instance
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
from spanlogger import log
|
|
183
|
+
|
|
184
|
+
log.info("Quick access without creating an instance")
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## License
|
|
188
|
+
|
|
189
|
+
MIT - by rowsvips | vmshops.mysellauth.com
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
spanlogger
|