pymon-sdk 0.1.3__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.
- pymon_sdk-0.1.3/PKG-INFO +41 -0
- pymon_sdk-0.1.3/README.md +18 -0
- pymon_sdk-0.1.3/pymon/__init__.py +6 -0
- pymon_sdk-0.1.3/pymon/client.py +75 -0
- pymon_sdk-0.1.3/pymon/decorators.py +72 -0
- pymon_sdk-0.1.3/pymon_sdk.egg-info/PKG-INFO +41 -0
- pymon_sdk-0.1.3/pymon_sdk.egg-info/SOURCES.txt +10 -0
- pymon_sdk-0.1.3/pymon_sdk.egg-info/dependency_links.txt +1 -0
- pymon_sdk-0.1.3/pymon_sdk.egg-info/requires.txt +1 -0
- pymon_sdk-0.1.3/pymon_sdk.egg-info/top_level.txt +1 -0
- pymon_sdk-0.1.3/pyproject.toml +34 -0
- pymon_sdk-0.1.3/setup.cfg +4 -0
pymon_sdk-0.1.3/PKG-INFO
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pymon-sdk
|
|
3
|
+
Version: 0.1.3
|
|
4
|
+
Summary: Monitor your Python jobs with one decorator.
|
|
5
|
+
Author-email: Antony Kimanzi <antony.kim345@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://pymon.dev
|
|
8
|
+
Project-URL: Repository, https://github.com/antony_kimanzi/pymon-python-sdk
|
|
9
|
+
Keywords: monitoring,cron,jobs,celery,alerts,devops
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
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: Topic :: System :: Monitoring
|
|
20
|
+
Requires-Python: >=3.8
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
Requires-Dist: requests>=2.28.0
|
|
23
|
+
|
|
24
|
+
# PyMon Python SDK 🐍
|
|
25
|
+
|
|
26
|
+
Monitor your Python jobs with one decorator. Get instant alerts with full stack traces when they fail.
|
|
27
|
+
|
|
28
|
+
## Why PyMon?
|
|
29
|
+
|
|
30
|
+
- 🐍 **One decorator:** No complex setup, no YAML files, no infrastructure changes.
|
|
31
|
+
- 📋 **Stack traces in alerts:** Know exactly which line of code failed instantly.
|
|
32
|
+
- ⚡ **Async support:** Works perfectly with `async`/`await` using `@monitor_async`.
|
|
33
|
+
- 🛡️ **Non-blocking:** If the PyMon API goes down, your script will *never* crash.
|
|
34
|
+
- 🆓 **Free forever:** No credit card, no hidden limits.
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
You can install the SDK directly via pip:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install pymon-sdk
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# PyMon Python SDK 🐍
|
|
2
|
+
|
|
3
|
+
Monitor your Python jobs with one decorator. Get instant alerts with full stack traces when they fail.
|
|
4
|
+
|
|
5
|
+
## Why PyMon?
|
|
6
|
+
|
|
7
|
+
- 🐍 **One decorator:** No complex setup, no YAML files, no infrastructure changes.
|
|
8
|
+
- 📋 **Stack traces in alerts:** Know exactly which line of code failed instantly.
|
|
9
|
+
- ⚡ **Async support:** Works perfectly with `async`/`await` using `@monitor_async`.
|
|
10
|
+
- 🛡️ **Non-blocking:** If the PyMon API goes down, your script will *never* crash.
|
|
11
|
+
- 🆓 **Free forever:** No credit card, no hidden limits.
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
You can install the SDK directly via pip:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install pymon-sdk
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
from datetime import datetime, timezone
|
|
2
|
+
import os
|
|
3
|
+
import traceback
|
|
4
|
+
from typing import Optional, Dict, Any
|
|
5
|
+
import requests
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Client:
|
|
9
|
+
"""Client for communicating with the PyMon API."""
|
|
10
|
+
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
api_key: Optional[str] = None,
|
|
14
|
+
base_url: Optional[str] = None,
|
|
15
|
+
timeout: int = 5,
|
|
16
|
+
):
|
|
17
|
+
# Read from environment variables if not passed explicitly
|
|
18
|
+
self.api_key = api_key or os.environ.get("PYMON_API_KEY")
|
|
19
|
+
self.base_url = base_url or os.environ.get("PYMON_API_BASE_URL", "http://localhost:8080/api/v1")
|
|
20
|
+
self.timeout = timeout
|
|
21
|
+
|
|
22
|
+
if not self.api_key:
|
|
23
|
+
raise ValueError(
|
|
24
|
+
"PyMon API Key is required."
|
|
25
|
+
"Set the PYMON_API_KEY environment variable or pass api_key"
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
def _get_headers(self) -> Dict[str, str]:
|
|
29
|
+
return {
|
|
30
|
+
"Authorization": f"Bearer {self.api_key}",
|
|
31
|
+
"Content-Type": "application/json",
|
|
32
|
+
"User-Agent": "pymon-python/0.1.0",
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
def ping_success(self, duration_ms: int) -> bool:
|
|
36
|
+
"""Send a success ping tp the backend"""
|
|
37
|
+
try:
|
|
38
|
+
url = f"{self.base_url}/ping/{self.api_key}"
|
|
39
|
+
payload = {"durationMs" : duration_ms}
|
|
40
|
+
|
|
41
|
+
response = requests.post(
|
|
42
|
+
url,
|
|
43
|
+
json=payload,
|
|
44
|
+
headers=self._get_headers(),
|
|
45
|
+
timeout=self.timeout,
|
|
46
|
+
)
|
|
47
|
+
response.raise_for_status()
|
|
48
|
+
return True
|
|
49
|
+
except requests.RequestException as e:
|
|
50
|
+
print(f"DEBUG: Ping failed -> {e}") # ADD THIS
|
|
51
|
+
return False
|
|
52
|
+
|
|
53
|
+
def report_failure(self, error: Exception) -> bool:
|
|
54
|
+
"""Report a failure with the full stack trace"""
|
|
55
|
+
try:
|
|
56
|
+
url = f"{self.base_url}/ping/{self.api_key}/fail"
|
|
57
|
+
|
|
58
|
+
payload = {
|
|
59
|
+
"errorType": type(error).__name__,
|
|
60
|
+
"errorMessage": str(error),
|
|
61
|
+
"stackTrace": traceback.format_exc(),
|
|
62
|
+
"occurredAt": datetime.now(timezone.utc).isoformat()
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
response = requests.post(
|
|
66
|
+
url,
|
|
67
|
+
json=payload,
|
|
68
|
+
headers=self._get_headers(),
|
|
69
|
+
timeout=self.timeout,
|
|
70
|
+
)
|
|
71
|
+
response.raise_for_status()
|
|
72
|
+
return True
|
|
73
|
+
except requests.RequestException as e:
|
|
74
|
+
print(f"DEBUG: Failure report failed -> {e}") # ADD THIS
|
|
75
|
+
return False
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
import time
|
|
3
|
+
from typing import Optional, Callable, Any
|
|
4
|
+
|
|
5
|
+
from pymon.client import Client
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def monitor(check_name: str, client: Optional[Client] = None):
|
|
9
|
+
"""
|
|
10
|
+
Decorator to monitor a synchronous function.
|
|
11
|
+
|
|
12
|
+
Usage:
|
|
13
|
+
@monitor("nightly-backup")
|
|
14
|
+
def backup():
|
|
15
|
+
...
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def decorator(func: Callable) -> Callable:
|
|
19
|
+
@functools.wraps(func)
|
|
20
|
+
def wrapper(*args, **kwargs) -> Any:
|
|
21
|
+
_client = client or Client()
|
|
22
|
+
start_time = time.time()
|
|
23
|
+
|
|
24
|
+
try:
|
|
25
|
+
# Run the user's function
|
|
26
|
+
result = func(*args, **kwargs)
|
|
27
|
+
|
|
28
|
+
# If iy succeeds, calculate time and send success ping
|
|
29
|
+
duration_ms = int((time.time() - start_time) * 1000)
|
|
30
|
+
_client.ping_success(duration_ms)
|
|
31
|
+
return result
|
|
32
|
+
|
|
33
|
+
except Exception as e:
|
|
34
|
+
# If it fails, report the failure, then re-raise the error
|
|
35
|
+
_client.report_failure(e)
|
|
36
|
+
raise e
|
|
37
|
+
|
|
38
|
+
return wrapper
|
|
39
|
+
return decorator
|
|
40
|
+
|
|
41
|
+
def monitor_async(check_name: str, client: Optional[Client] = None):
|
|
42
|
+
"""
|
|
43
|
+
Decorator to monitor an asynchronous function.
|
|
44
|
+
|
|
45
|
+
Usage:
|
|
46
|
+
@monitor_async("daily-report")
|
|
47
|
+
async def generate_report():
|
|
48
|
+
...
|
|
49
|
+
"""
|
|
50
|
+
def decorator(func: Callable) -> Callable:
|
|
51
|
+
@functools.wraps(func)
|
|
52
|
+
async def wrapper(*args, **kwargs) -> Any:
|
|
53
|
+
_client = client or Client()
|
|
54
|
+
start_time = time.time()
|
|
55
|
+
|
|
56
|
+
try:
|
|
57
|
+
# Run the user's async function
|
|
58
|
+
result = await func(*args, **kwargs)
|
|
59
|
+
|
|
60
|
+
# Send success ping
|
|
61
|
+
duration_ms = int((time.time() - start_time) * 1000)
|
|
62
|
+
_client.ping_success(duration_ms)
|
|
63
|
+
|
|
64
|
+
return result
|
|
65
|
+
|
|
66
|
+
except Exception as e:
|
|
67
|
+
# Report failure, then re-raise
|
|
68
|
+
_client.report_failure(e)
|
|
69
|
+
raise e
|
|
70
|
+
|
|
71
|
+
return wrapper
|
|
72
|
+
return decorator
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pymon-sdk
|
|
3
|
+
Version: 0.1.3
|
|
4
|
+
Summary: Monitor your Python jobs with one decorator.
|
|
5
|
+
Author-email: Antony Kimanzi <antony.kim345@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://pymon.dev
|
|
8
|
+
Project-URL: Repository, https://github.com/antony_kimanzi/pymon-python-sdk
|
|
9
|
+
Keywords: monitoring,cron,jobs,celery,alerts,devops
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
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: Topic :: System :: Monitoring
|
|
20
|
+
Requires-Python: >=3.8
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
Requires-Dist: requests>=2.28.0
|
|
23
|
+
|
|
24
|
+
# PyMon Python SDK 🐍
|
|
25
|
+
|
|
26
|
+
Monitor your Python jobs with one decorator. Get instant alerts with full stack traces when they fail.
|
|
27
|
+
|
|
28
|
+
## Why PyMon?
|
|
29
|
+
|
|
30
|
+
- 🐍 **One decorator:** No complex setup, no YAML files, no infrastructure changes.
|
|
31
|
+
- 📋 **Stack traces in alerts:** Know exactly which line of code failed instantly.
|
|
32
|
+
- ⚡ **Async support:** Works perfectly with `async`/`await` using `@monitor_async`.
|
|
33
|
+
- 🛡️ **Non-blocking:** If the PyMon API goes down, your script will *never* crash.
|
|
34
|
+
- 🆓 **Free forever:** No credit card, no hidden limits.
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
You can install the SDK directly via pip:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install pymon-sdk
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
pymon/__init__.py
|
|
4
|
+
pymon/client.py
|
|
5
|
+
pymon/decorators.py
|
|
6
|
+
pymon_sdk.egg-info/PKG-INFO
|
|
7
|
+
pymon_sdk.egg-info/SOURCES.txt
|
|
8
|
+
pymon_sdk.egg-info/dependency_links.txt
|
|
9
|
+
pymon_sdk.egg-info/requires.txt
|
|
10
|
+
pymon_sdk.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
requests>=2.28.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pymon
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pymon-sdk"
|
|
7
|
+
version = "0.1.3"
|
|
8
|
+
description = "Monitor your Python jobs with one decorator."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Antony Kimanzi", email = "antony.kim345@gmail.com"}
|
|
14
|
+
]
|
|
15
|
+
keywords = ["monitoring", "cron", "jobs", "celery", "alerts", "devops"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.8",
|
|
22
|
+
"Programming Language :: Python :: 3.9",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Topic :: System :: Monitoring",
|
|
27
|
+
]
|
|
28
|
+
dependencies = [
|
|
29
|
+
"requests>=2.28.0"
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.urls]
|
|
33
|
+
Homepage = "https://pymon.dev"
|
|
34
|
+
Repository = "https://github.com/antony_kimanzi/pymon-python-sdk"
|