script-reporter 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.
- script_reporter-0.1.0/LICENSE +21 -0
- script_reporter-0.1.0/PKG-INFO +103 -0
- script_reporter-0.1.0/README.md +85 -0
- script_reporter-0.1.0/pyproject.toml +28 -0
- script_reporter-0.1.0/setup.cfg +4 -0
- script_reporter-0.1.0/src/script_reporter/__init__.py +3 -0
- script_reporter-0.1.0/src/script_reporter/adapters/__init__.py +6 -0
- script_reporter-0.1.0/src/script_reporter/adapters/base.py +3 -0
- script_reporter-0.1.0/src/script_reporter/adapters/console.py +6 -0
- script_reporter-0.1.0/src/script_reporter/adapters/discord.py +50 -0
- script_reporter-0.1.0/src/script_reporter/adapters/telegram.py +46 -0
- script_reporter-0.1.0/src/script_reporter/reporter.py +67 -0
- script_reporter-0.1.0/src/script_reporter.egg-info/PKG-INFO +103 -0
- script_reporter-0.1.0/src/script_reporter.egg-info/SOURCES.txt +14 -0
- script_reporter-0.1.0/src/script_reporter.egg-info/dependency_links.txt +1 -0
- script_reporter-0.1.0/src/script_reporter.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Yoonbae Cho
|
|
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,103 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: script-reporter
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A lightweight status reporter for Python scripts with Discord and Telegram support
|
|
5
|
+
Author-email: Yoonbae Cho <y@xcv.kr>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/yoonbae81/script-reporter
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/yoonbae81/script-reporter/issues
|
|
9
|
+
Keywords: reporter,notification,discord,telegram,script,monitoring
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
14
|
+
Requires-Python: >=3.7
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Dynamic: license-file
|
|
18
|
+
|
|
19
|
+
# script-reporter 🚀
|
|
20
|
+
|
|
21
|
+
A lightweight, zero-dependency Python status reporter designed for automation scripts and cron jobs. Easily report execution progress, stages, and results to **Console**, **Discord**, and **Telegram**.
|
|
22
|
+
|
|
23
|
+
## ✨ Key Features
|
|
24
|
+
|
|
25
|
+
- **Zero External Dependencies**: Uses Python standard library only (`urllib`).
|
|
26
|
+
- **Multi-Channel**: Simultaneous reporting to Console, Discord (Webhooks), and Telegram (Bot API).
|
|
27
|
+
- **Stage Tracking**: Monitor exactly where your script is (e.g., `SETUP` -> `PROCESSING` -> `COMPLETE`).
|
|
28
|
+
- **Error Transparency**: Automatically attaches tracebacks on failure.
|
|
29
|
+
- **Duration Tracking**: Automatically calculates and reports execution time.
|
|
30
|
+
- **CI/CD & Cron Friendly**: Standardized JSON output for logs makes it easy for other tools to parse.
|
|
31
|
+
|
|
32
|
+
## 📦 Installation
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install script-reporter
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## 🚀 Quick Start
|
|
39
|
+
|
|
40
|
+
### 1. Simple Usage (Auto-reporitng)
|
|
41
|
+
|
|
42
|
+
Set simple environment variables to enable channels:
|
|
43
|
+
- `REPORTER_DISCORD_WEBHOOK`: Discord Webhook URL
|
|
44
|
+
- `REPORTER_TELEGRAM_TOKEN` & `REPORTER_TELEGRAM_CHAT_ID`: Telegram Bot Token and Chat ID
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from script_reporter import ScriptReporter
|
|
48
|
+
import traceback
|
|
49
|
+
|
|
50
|
+
# Initialize with a title (auto-detects Discord/Telegram from Env)
|
|
51
|
+
reporter = ScriptReporter("My Automation Task")
|
|
52
|
+
|
|
53
|
+
try:
|
|
54
|
+
# 1. Start a stage
|
|
55
|
+
reporter.stage("DATA_FETCH")
|
|
56
|
+
# ... your logic ...
|
|
57
|
+
|
|
58
|
+
# 2. Update stage as you progress
|
|
59
|
+
reporter.stage("PROCESSING")
|
|
60
|
+
# ... your logic ...
|
|
61
|
+
|
|
62
|
+
# 3. Report success with optional detail dictionary
|
|
63
|
+
reporter.success({"items_processed": 100, "status": "all_good"})
|
|
64
|
+
|
|
65
|
+
except Exception:
|
|
66
|
+
# 4. Report failure with traceback
|
|
67
|
+
reporter.fail(traceback.format_exc())
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 2. Manual Configuration
|
|
71
|
+
|
|
72
|
+
Explicitly control adapters without environment variables:
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
from script_reporter import ScriptReporter, ConsoleAdapter, DiscordAdapter, TelegramAdapter
|
|
76
|
+
|
|
77
|
+
adapters = [
|
|
78
|
+
ConsoleAdapter(),
|
|
79
|
+
DiscordAdapter(webhook_url="https://discord.com/api/webhooks/..."),
|
|
80
|
+
TelegramAdapter(token="BOT_TOKEN", chat_id="CHAT_ID")
|
|
81
|
+
]
|
|
82
|
+
|
|
83
|
+
reporter = ScriptReporter("Manual Config Task", adapters=adapters)
|
|
84
|
+
reporter.success({"msg": "Hello from code!"})
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## 📊 JSON Log Format
|
|
88
|
+
|
|
89
|
+
`ConsoleAdapter` prints a machine-readable JSON line starting with `__RESULT__`:
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
__RESULT__ {"title": "My Task", "host": "server-01", "stage": "COMPLETE", "status": "SUCCESS", "duration": "1m 30s", "detail": {"processed": 5}}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## 🛠Advanced Concepts
|
|
96
|
+
|
|
97
|
+
- **Stages**: Use `reporter.stage("NAME")` to track progress. If `reporter.fail()` is called, it identifies the last successful stage.
|
|
98
|
+
- **Duration**: Tracks time from `ScriptReporter()` initialization to `success()`/`fail()` call.
|
|
99
|
+
- **Discord Rich Embeds**: `DiscordAdapter` automatically formats details and errors into beautiful rich embeds.
|
|
100
|
+
|
|
101
|
+
## 📄 License
|
|
102
|
+
|
|
103
|
+
MIT License. See [LICENSE](LICENSE) for more details.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# script-reporter 🚀
|
|
2
|
+
|
|
3
|
+
A lightweight, zero-dependency Python status reporter designed for automation scripts and cron jobs. Easily report execution progress, stages, and results to **Console**, **Discord**, and **Telegram**.
|
|
4
|
+
|
|
5
|
+
## ✨ Key Features
|
|
6
|
+
|
|
7
|
+
- **Zero External Dependencies**: Uses Python standard library only (`urllib`).
|
|
8
|
+
- **Multi-Channel**: Simultaneous reporting to Console, Discord (Webhooks), and Telegram (Bot API).
|
|
9
|
+
- **Stage Tracking**: Monitor exactly where your script is (e.g., `SETUP` -> `PROCESSING` -> `COMPLETE`).
|
|
10
|
+
- **Error Transparency**: Automatically attaches tracebacks on failure.
|
|
11
|
+
- **Duration Tracking**: Automatically calculates and reports execution time.
|
|
12
|
+
- **CI/CD & Cron Friendly**: Standardized JSON output for logs makes it easy for other tools to parse.
|
|
13
|
+
|
|
14
|
+
## 📦 Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install script-reporter
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## 🚀 Quick Start
|
|
21
|
+
|
|
22
|
+
### 1. Simple Usage (Auto-reporitng)
|
|
23
|
+
|
|
24
|
+
Set simple environment variables to enable channels:
|
|
25
|
+
- `REPORTER_DISCORD_WEBHOOK`: Discord Webhook URL
|
|
26
|
+
- `REPORTER_TELEGRAM_TOKEN` & `REPORTER_TELEGRAM_CHAT_ID`: Telegram Bot Token and Chat ID
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from script_reporter import ScriptReporter
|
|
30
|
+
import traceback
|
|
31
|
+
|
|
32
|
+
# Initialize with a title (auto-detects Discord/Telegram from Env)
|
|
33
|
+
reporter = ScriptReporter("My Automation Task")
|
|
34
|
+
|
|
35
|
+
try:
|
|
36
|
+
# 1. Start a stage
|
|
37
|
+
reporter.stage("DATA_FETCH")
|
|
38
|
+
# ... your logic ...
|
|
39
|
+
|
|
40
|
+
# 2. Update stage as you progress
|
|
41
|
+
reporter.stage("PROCESSING")
|
|
42
|
+
# ... your logic ...
|
|
43
|
+
|
|
44
|
+
# 3. Report success with optional detail dictionary
|
|
45
|
+
reporter.success({"items_processed": 100, "status": "all_good"})
|
|
46
|
+
|
|
47
|
+
except Exception:
|
|
48
|
+
# 4. Report failure with traceback
|
|
49
|
+
reporter.fail(traceback.format_exc())
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 2. Manual Configuration
|
|
53
|
+
|
|
54
|
+
Explicitly control adapters without environment variables:
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
from script_reporter import ScriptReporter, ConsoleAdapter, DiscordAdapter, TelegramAdapter
|
|
58
|
+
|
|
59
|
+
adapters = [
|
|
60
|
+
ConsoleAdapter(),
|
|
61
|
+
DiscordAdapter(webhook_url="https://discord.com/api/webhooks/..."),
|
|
62
|
+
TelegramAdapter(token="BOT_TOKEN", chat_id="CHAT_ID")
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
reporter = ScriptReporter("Manual Config Task", adapters=adapters)
|
|
66
|
+
reporter.success({"msg": "Hello from code!"})
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## 📊 JSON Log Format
|
|
70
|
+
|
|
71
|
+
`ConsoleAdapter` prints a machine-readable JSON line starting with `__RESULT__`:
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
__RESULT__ {"title": "My Task", "host": "server-01", "stage": "COMPLETE", "status": "SUCCESS", "duration": "1m 30s", "detail": {"processed": 5}}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## 🛠Advanced Concepts
|
|
78
|
+
|
|
79
|
+
- **Stages**: Use `reporter.stage("NAME")` to track progress. If `reporter.fail()` is called, it identifies the last successful stage.
|
|
80
|
+
- **Duration**: Tracks time from `ScriptReporter()` initialization to `success()`/`fail()` call.
|
|
81
|
+
- **Discord Rich Embeds**: `DiscordAdapter` automatically formats details and errors into beautiful rich embeds.
|
|
82
|
+
|
|
83
|
+
## 📄 License
|
|
84
|
+
|
|
85
|
+
MIT License. See [LICENSE](LICENSE) for more details.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "script-reporter"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name = "Yoonbae Cho", email = "y@xcv.kr" },
|
|
10
|
+
]
|
|
11
|
+
description = "A lightweight status reporter for Python scripts with Discord and Telegram support"
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
requires-python = ">=3.7"
|
|
14
|
+
keywords = ["reporter", "notification", "discord", "telegram", "script", "monitoring"]
|
|
15
|
+
license = { text = "MIT" }
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"License :: OSI Approved :: MIT License",
|
|
19
|
+
"Operating System :: OS Independent",
|
|
20
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
[project.urls]
|
|
24
|
+
"Homepage" = "https://github.com/yoonbae81/script-reporter"
|
|
25
|
+
"Bug Tracker" = "https://github.com/yoonbae81/script-reporter/issues"
|
|
26
|
+
|
|
27
|
+
[tool.setuptools.packages.find]
|
|
28
|
+
where = ["src"]
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
import time
|
|
4
|
+
import urllib.request
|
|
5
|
+
from .base import BaseAdapter
|
|
6
|
+
|
|
7
|
+
class DiscordAdapter(BaseAdapter):
|
|
8
|
+
def __init__(self, webhook_url=None):
|
|
9
|
+
self.webhook_url = webhook_url or os.environ.get('REPORTER_DISCORD_WEBHOOK')
|
|
10
|
+
|
|
11
|
+
def send(self, result):
|
|
12
|
+
if not self.webhook_url:
|
|
13
|
+
return
|
|
14
|
+
|
|
15
|
+
status_emoji = "" # Removed noisy emojis
|
|
16
|
+
title = result.get('title', 'Execution')
|
|
17
|
+
|
|
18
|
+
embed = {
|
|
19
|
+
"title": f"{title} Result: {result['status']}",
|
|
20
|
+
"color": 0x00ff00 if result['status'] == "SUCCESS" else 0xff0000,
|
|
21
|
+
"fields": [
|
|
22
|
+
{"name": "Host", "value": result['host'], "inline": True},
|
|
23
|
+
{"name": "Stage", "value": result['stage'], "inline": True},
|
|
24
|
+
{"name": "Duration", "value": result['duration'], "inline": True},
|
|
25
|
+
],
|
|
26
|
+
"timestamp": time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if result.get('detail'):
|
|
30
|
+
detail_lines = []
|
|
31
|
+
for key, value in result['detail'].items():
|
|
32
|
+
label = key.replace('_', ' ').title()
|
|
33
|
+
detail_lines.append(f"**{label}**: {value}")
|
|
34
|
+
if detail_lines:
|
|
35
|
+
embed["description"] = "\n".join(detail_lines)
|
|
36
|
+
|
|
37
|
+
if result['status'] == "FAIL" and result.get('trace'):
|
|
38
|
+
trace = result['trace']
|
|
39
|
+
if len(trace) > 1000:
|
|
40
|
+
trace = trace[:1000] + "..."
|
|
41
|
+
embed["fields"].append({"name": "Error Trace", "value": f"```python\n{trace}\n```"})
|
|
42
|
+
|
|
43
|
+
data = json.dumps({"embeds": [embed]}).encode('utf-8')
|
|
44
|
+
req = urllib.request.Request(self.webhook_url, data=data, headers={'Content-Type': 'application/json', 'User-Agent': 'Result-Bot'})
|
|
45
|
+
|
|
46
|
+
try:
|
|
47
|
+
with urllib.request.urlopen(req, timeout=10) as response:
|
|
48
|
+
pass
|
|
49
|
+
except Exception as e:
|
|
50
|
+
print(f"Failed to send Discord notification: {e}")
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
import urllib.request
|
|
4
|
+
from .base import BaseAdapter
|
|
5
|
+
|
|
6
|
+
class TelegramAdapter(BaseAdapter):
|
|
7
|
+
def __init__(self, token=None, chat_id=None):
|
|
8
|
+
self.token = token or os.environ.get('REPORTER_TELEGRAM_TOKEN')
|
|
9
|
+
self.chat_id = chat_id or os.environ.get('REPORTER_TELEGRAM_CHAT_ID')
|
|
10
|
+
|
|
11
|
+
def send(self, result):
|
|
12
|
+
if not self.token or not self.chat_id:
|
|
13
|
+
return
|
|
14
|
+
|
|
15
|
+
status_emoji = "" # Removed noisy emojis
|
|
16
|
+
title = result.get('title', 'Execution')
|
|
17
|
+
text = f"*{title} Result: {result['status']}*\n\n"
|
|
18
|
+
text += f"- *Host:* {result['host']}\n"
|
|
19
|
+
text += f"- *Stage:* {result['stage']}\n"
|
|
20
|
+
text += f"- *Duration:* {result['duration']}\n"
|
|
21
|
+
|
|
22
|
+
if result.get('detail'):
|
|
23
|
+
for key, value in result['detail'].items():
|
|
24
|
+
label = key.replace('_', ' ').title()
|
|
25
|
+
text += f"- *{label}:* {value}\n"
|
|
26
|
+
|
|
27
|
+
if result['status'] == "FAIL" and result.get('trace'):
|
|
28
|
+
trace = result['trace']
|
|
29
|
+
if len(trace) > 500:
|
|
30
|
+
trace = trace[:500] + "..."
|
|
31
|
+
text += f"\n*Error Trace:*\n`{trace}`"
|
|
32
|
+
|
|
33
|
+
url = f"https://api.telegram.org/bot{self.token}/sendMessage"
|
|
34
|
+
data = json.dumps({
|
|
35
|
+
"chat_id": self.chat_id,
|
|
36
|
+
"text": text,
|
|
37
|
+
"parse_mode": "Markdown"
|
|
38
|
+
}).encode('utf-8')
|
|
39
|
+
|
|
40
|
+
req = urllib.request.Request(url, data=data, headers={'Content-Type': 'application/json'})
|
|
41
|
+
|
|
42
|
+
try:
|
|
43
|
+
with urllib.request.urlopen(req, timeout=10) as response:
|
|
44
|
+
pass
|
|
45
|
+
except Exception as e:
|
|
46
|
+
print(f"Failed to send Telegram notification: {e}")
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import socket
|
|
3
|
+
import time
|
|
4
|
+
import os
|
|
5
|
+
from .adapters import ConsoleAdapter, DiscordAdapter, TelegramAdapter
|
|
6
|
+
|
|
7
|
+
class ScriptReporter:
|
|
8
|
+
def __init__(self, title="Task", adapters=None):
|
|
9
|
+
self.title = title
|
|
10
|
+
self.host = socket.gethostname()
|
|
11
|
+
self.start_time = time.time()
|
|
12
|
+
self.current_stage = "INIT"
|
|
13
|
+
|
|
14
|
+
if adapters is None:
|
|
15
|
+
# Default adapters: Console always
|
|
16
|
+
self.adapters = [ConsoleAdapter()]
|
|
17
|
+
|
|
18
|
+
# Auto-detect Discord
|
|
19
|
+
if os.environ.get('REPORTER_DISCORD_WEBHOOK'):
|
|
20
|
+
self.adapters.append(DiscordAdapter())
|
|
21
|
+
|
|
22
|
+
# Auto-detect Telegram
|
|
23
|
+
if os.environ.get('REPORTER_TELEGRAM_TOKEN') and os.environ.get('REPORTER_TELEGRAM_CHAT_ID'):
|
|
24
|
+
self.adapters.append(TelegramAdapter())
|
|
25
|
+
else:
|
|
26
|
+
self.adapters = adapters
|
|
27
|
+
|
|
28
|
+
def stage(self, stage_name):
|
|
29
|
+
self.current_stage = stage_name
|
|
30
|
+
|
|
31
|
+
def _get_duration(self):
|
|
32
|
+
duration_sec = time.time() - self.start_time
|
|
33
|
+
if duration_sec < 60:
|
|
34
|
+
return f"{int(duration_sec)}s"
|
|
35
|
+
else:
|
|
36
|
+
minutes = int(duration_sec // 60)
|
|
37
|
+
seconds = int(duration_sec % 60)
|
|
38
|
+
return f"{minutes}m {seconds}s"
|
|
39
|
+
|
|
40
|
+
def _notify(self, result_data):
|
|
41
|
+
for adapter in self.adapters:
|
|
42
|
+
try:
|
|
43
|
+
adapter.send(result_data)
|
|
44
|
+
except Exception as e:
|
|
45
|
+
print(f"Adapter {adapter.__class__.__name__} failed: {e}")
|
|
46
|
+
|
|
47
|
+
def success(self, detail=None):
|
|
48
|
+
result_data = {
|
|
49
|
+
"title": self.title,
|
|
50
|
+
"host": self.host,
|
|
51
|
+
"stage": "COMPLETE",
|
|
52
|
+
"status": "SUCCESS",
|
|
53
|
+
"duration": self._get_duration(),
|
|
54
|
+
"detail": detail or {}
|
|
55
|
+
}
|
|
56
|
+
self._notify(result_data)
|
|
57
|
+
|
|
58
|
+
def fail(self, error_trace):
|
|
59
|
+
result_data = {
|
|
60
|
+
"title": self.title,
|
|
61
|
+
"host": self.host,
|
|
62
|
+
"stage": self.current_stage,
|
|
63
|
+
"status": "FAIL",
|
|
64
|
+
"duration": self._get_duration(),
|
|
65
|
+
"trace": error_trace
|
|
66
|
+
}
|
|
67
|
+
self._notify(result_data)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: script-reporter
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A lightweight status reporter for Python scripts with Discord and Telegram support
|
|
5
|
+
Author-email: Yoonbae Cho <y@xcv.kr>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/yoonbae81/script-reporter
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/yoonbae81/script-reporter/issues
|
|
9
|
+
Keywords: reporter,notification,discord,telegram,script,monitoring
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
14
|
+
Requires-Python: >=3.7
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Dynamic: license-file
|
|
18
|
+
|
|
19
|
+
# script-reporter 🚀
|
|
20
|
+
|
|
21
|
+
A lightweight, zero-dependency Python status reporter designed for automation scripts and cron jobs. Easily report execution progress, stages, and results to **Console**, **Discord**, and **Telegram**.
|
|
22
|
+
|
|
23
|
+
## ✨ Key Features
|
|
24
|
+
|
|
25
|
+
- **Zero External Dependencies**: Uses Python standard library only (`urllib`).
|
|
26
|
+
- **Multi-Channel**: Simultaneous reporting to Console, Discord (Webhooks), and Telegram (Bot API).
|
|
27
|
+
- **Stage Tracking**: Monitor exactly where your script is (e.g., `SETUP` -> `PROCESSING` -> `COMPLETE`).
|
|
28
|
+
- **Error Transparency**: Automatically attaches tracebacks on failure.
|
|
29
|
+
- **Duration Tracking**: Automatically calculates and reports execution time.
|
|
30
|
+
- **CI/CD & Cron Friendly**: Standardized JSON output for logs makes it easy for other tools to parse.
|
|
31
|
+
|
|
32
|
+
## 📦 Installation
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install script-reporter
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## 🚀 Quick Start
|
|
39
|
+
|
|
40
|
+
### 1. Simple Usage (Auto-reporitng)
|
|
41
|
+
|
|
42
|
+
Set simple environment variables to enable channels:
|
|
43
|
+
- `REPORTER_DISCORD_WEBHOOK`: Discord Webhook URL
|
|
44
|
+
- `REPORTER_TELEGRAM_TOKEN` & `REPORTER_TELEGRAM_CHAT_ID`: Telegram Bot Token and Chat ID
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from script_reporter import ScriptReporter
|
|
48
|
+
import traceback
|
|
49
|
+
|
|
50
|
+
# Initialize with a title (auto-detects Discord/Telegram from Env)
|
|
51
|
+
reporter = ScriptReporter("My Automation Task")
|
|
52
|
+
|
|
53
|
+
try:
|
|
54
|
+
# 1. Start a stage
|
|
55
|
+
reporter.stage("DATA_FETCH")
|
|
56
|
+
# ... your logic ...
|
|
57
|
+
|
|
58
|
+
# 2. Update stage as you progress
|
|
59
|
+
reporter.stage("PROCESSING")
|
|
60
|
+
# ... your logic ...
|
|
61
|
+
|
|
62
|
+
# 3. Report success with optional detail dictionary
|
|
63
|
+
reporter.success({"items_processed": 100, "status": "all_good"})
|
|
64
|
+
|
|
65
|
+
except Exception:
|
|
66
|
+
# 4. Report failure with traceback
|
|
67
|
+
reporter.fail(traceback.format_exc())
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 2. Manual Configuration
|
|
71
|
+
|
|
72
|
+
Explicitly control adapters without environment variables:
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
from script_reporter import ScriptReporter, ConsoleAdapter, DiscordAdapter, TelegramAdapter
|
|
76
|
+
|
|
77
|
+
adapters = [
|
|
78
|
+
ConsoleAdapter(),
|
|
79
|
+
DiscordAdapter(webhook_url="https://discord.com/api/webhooks/..."),
|
|
80
|
+
TelegramAdapter(token="BOT_TOKEN", chat_id="CHAT_ID")
|
|
81
|
+
]
|
|
82
|
+
|
|
83
|
+
reporter = ScriptReporter("Manual Config Task", adapters=adapters)
|
|
84
|
+
reporter.success({"msg": "Hello from code!"})
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## 📊 JSON Log Format
|
|
88
|
+
|
|
89
|
+
`ConsoleAdapter` prints a machine-readable JSON line starting with `__RESULT__`:
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
__RESULT__ {"title": "My Task", "host": "server-01", "stage": "COMPLETE", "status": "SUCCESS", "duration": "1m 30s", "detail": {"processed": 5}}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## 🛠Advanced Concepts
|
|
96
|
+
|
|
97
|
+
- **Stages**: Use `reporter.stage("NAME")` to track progress. If `reporter.fail()` is called, it identifies the last successful stage.
|
|
98
|
+
- **Duration**: Tracks time from `ScriptReporter()` initialization to `success()`/`fail()` call.
|
|
99
|
+
- **Discord Rich Embeds**: `DiscordAdapter` automatically formats details and errors into beautiful rich embeds.
|
|
100
|
+
|
|
101
|
+
## 📄 License
|
|
102
|
+
|
|
103
|
+
MIT License. See [LICENSE](LICENSE) for more details.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/script_reporter/__init__.py
|
|
5
|
+
src/script_reporter/reporter.py
|
|
6
|
+
src/script_reporter.egg-info/PKG-INFO
|
|
7
|
+
src/script_reporter.egg-info/SOURCES.txt
|
|
8
|
+
src/script_reporter.egg-info/dependency_links.txt
|
|
9
|
+
src/script_reporter.egg-info/top_level.txt
|
|
10
|
+
src/script_reporter/adapters/__init__.py
|
|
11
|
+
src/script_reporter/adapters/base.py
|
|
12
|
+
src/script_reporter/adapters/console.py
|
|
13
|
+
src/script_reporter/adapters/discord.py
|
|
14
|
+
src/script_reporter/adapters/telegram.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
script_reporter
|