Skip to content

Commit 56e8b75

Browse files
committed
initial commit
0 parents  commit 56e8b75

File tree

10 files changed

+363
-0
lines changed

10 files changed

+363
-0
lines changed

.github/dependabot.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: "pip"
4+
directory: "/"
5+
schedule:
6+
interval: "daily"
7+
open-pull-requests-limit: 5
8+
commit-message:
9+
prefix: "chore"
10+
include: "scope"
11+
assignees:
12+
- "psyb0t"
13+
labels:
14+
- "dependencies"
15+
- "automated pr"

.github/workflows/pipeline.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
name: pipeline
2+
3+
on: [push]
4+
5+
jobs:
6+
call-python-package-workflow:
7+
uses: psyb0t/reusable-github-workflows/.github/workflows/python-package-workflow.yml@master
8+
9+
with:
10+
python_version: "3.12.0"
11+
install_dependencies_command: "make dep"
12+
build_command: "make build"
13+
dist_dir: "dist"
14+
15+
secrets:
16+
pypi_api_token: ${{ secrets.PYPI_API_TOKEN }}

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
venv
2+
__pycache__
3+
dist

LICENSE

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
2+
Version 2, December 2004
3+
4+
Copyright (C) 2024 Ciprian Mandache <ciprian.51k.eu - psyb0t@51k.eu>
5+
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
6+
7+
Everyone is permitted to copy and distribute verbatim or modified
8+
copies of this license document, and changing it is allowed as long
9+
as the name is changed.
10+
11+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
12+
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
13+
14+
0. You just DO WHAT THE FUCK YOU WANT TO.

Makefile

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.PHONY: dep build clean help
2+
3+
dep: ## Install dependencies
4+
python -m pip install build
5+
6+
build: ## Build the project
7+
python -m build
8+
9+
clean: ## Clean the build artifacts
10+
rm -rf ./dist
11+
12+
help: ## Display this help message
13+
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

README.md

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
# 🚀 telegram-logger-client: Your Log's New Best Friend
2+
3+
Welcome to the telegram-logger-client - where your logs go to become stars!
4+
5+
## 🛠 Prerequisites
6+
7+
Before you dive in, make sure you've got your backstage pass ready:
8+
9+
1. You'll need to set up and run the telegram-logger service. It's like the bouncer at the club - without it, your logs aren't getting in.
10+
11+
2. Head over to [https://github.com/psyb0t/telegram-logger](https://github.com/psyb0t/telegram-logger) for the VIP instructions on setting up the telegram-logger service.
12+
13+
3. Once you've got that service up and running, come back here and let's make some noise!
14+
15+
## 🎭 Installation (No Secret Handshake Required)
16+
17+
Install this badass as a module and executable:
18+
19+
```shell
20+
pip install telegram-logger-client
21+
```
22+
23+
Go with `pipx` to just use it as an executable:
24+
25+
```shell
26+
pipx install telegram-logger-client
27+
```
28+
29+
## 🕹️ Usage (AKA How to Make Some Noise)
30+
31+
### 🐍 As a Python Module
32+
33+
Summon the TelegramLoggerClient in your Python code:
34+
35+
```python
36+
from telegram_logger_client import TelegramLoggerClient
37+
38+
# Create your logger
39+
logger = TelegramLoggerClient("https://your-logger-url.com", "your-secret-token")
40+
41+
# Send a log (it's like tweeting, but geekier)
42+
logger.send_log(
43+
caller="CoffeeBot",
44+
level="warning",
45+
message="Coffee levels critically low!",
46+
error="Caffeine deficiency detected",
47+
request_id="coffee-run-42",
48+
trace_id="from-bed-to-coffee-machine",
49+
span_id="mug-to-mouth",
50+
data={"coffee_type": "Espresso", "sugar": False, "milk": "Oat"}
51+
)
52+
```
53+
54+
### 🖥️ Command Line Magic
55+
56+
First, set up your secret lair:
57+
58+
```shell
59+
export TELEGRAM_LOGGER_BASE_URL=https://your-logger-url.com
60+
export TELEGRAM_LOGGER_X_ID=your-secret-token
61+
```
62+
63+
Now, shout into the void (or just send a log):
64+
65+
```shell
66+
telegram-logger-client \
67+
--caller "WeatherBot" \
68+
--level "info" \
69+
--message "It's raining cats and dogs!" \
70+
--error "Umbrella malfunction" \
71+
--request-id "weather-101" \
72+
--trace-id "cloud-to-ground" \
73+
--span-id "drop-to-splash" \
74+
--data '{"temperature": "chilly", "wind": "breezy"}'
75+
```
76+
77+
Want to see every little detail? Add the `--debug` flag:
78+
79+
```shell
80+
telegram-logger-client \
81+
--debug \
82+
--caller "WeatherBot" \
83+
--level "info" \
84+
--message "It's raining cats and dogs!"
85+
```
86+
87+
## 🎭 Logging Levels (Choose Your Adventure)
88+
89+
The client itself has two modes:
90+
91+
- Normal Mode (default): "Just the highlights" mode
92+
- Debug Mode: "I can hear a pin drop" mode
93+
94+
Your logs, on the other hand, can be as dramatic as you want:
95+
96+
- "info": "Just FYI" level
97+
- "warning": "Hmm, that's interesting" level
98+
- "error": "Houston, we have a problem" level
99+
100+
## 🧙‍♂️ API Reference (The Boring but Important Bit)
101+
102+
### 🔮 TelegramLoggerClient
103+
104+
#### `__init__(base_url: str, x_id: str)`
105+
106+
Create your logger. Feed it URLs and tokens.
107+
108+
#### `send_log(...)`
109+
110+
Send your log on a grand adventure. Pack its bags with:
111+
112+
- `caller`: Who's making all this noise?
113+
- `level`: How important is this, really?
114+
- `message`: What's the scoop?
115+
- `error`: What went boom?
116+
- `request_id`: A unique ID for this particular escapade
117+
- `trace_id`: For retracing your steps
118+
- `span_id`: A slice of time in the grand timeline
119+
- `data`: Any extra bits and bobs
120+
121+
Returns a `requests.Response` object (a postcard from your log's journey).
122+
123+
## 🗝️ Environment Variables (Your Logger's Secret Code)
124+
125+
- `TELEGRAM_LOGGER_BASE_URL`: Where your logs call home
126+
- `TELEGRAM_LOGGER_X_ID`: Your logger's super-secret identity
127+
128+
## 🎲 Command Line Arguments (For When You're Feeling Bossy)
129+
130+
- `--debug`: Unleash the full power of logging (optional)
131+
- `--base-url`: A new home for your logs
132+
- `--x-id`: A new secret identity
133+
- `--caller`: Who's calling?
134+
- `--level`: On a scale of "meh" to "THE WORLD IS ENDING!"
135+
- `--message`: Your log's 15 minutes of fame
136+
- `--error`: What's gone sideways?
137+
- `--request-id`: This log's personal serial number
138+
- `--trace-id`: Breadcrumbs in the digital forest
139+
- `--span-id`: A moment in time
140+
- `--data`: Everything else but the kitchen sink
141+
142+
Remember: Command line arguments are the divas of the coding world - they always steal the show from environment variables.
143+
144+
## 📜 License (The Fine Print)
145+
146+
This project is unleashed under the WTFPL License – Do What The F\*\*k You Want To Public License. Your imagination is the only limit, push it to the boundaries!
147+
148+
Now go forth and log like there's no tomorrow! May your errors be few and your insights be plentiful. Happy logging! 📝🚀

pyproject.toml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[build-system]
2+
requires = ["hatchling"]
3+
build-backend = "hatchling.build"
4+
5+
[project]
6+
name = "telegram-logger-client"
7+
version = "0.1.0"
8+
authors = [{ name = "Ciprian Mandache", email = "psyb0t@51k.eu" }]
9+
description = "A Python client for the telegram-logger service"
10+
readme = "README.md"
11+
requires-python = ">=3.6"
12+
classifiers = [
13+
"Programming Language :: Python :: 3",
14+
"Operating System :: OS Independent",
15+
]
16+
dependencies = ["requests>=2.32.3"]
17+
18+
[project.urls]
19+
Homepage = "https://github.com/psyb0t/py-telegram-logger-client"
20+
Issues = "https://github.com/psyb0t/py-telegram-logger-client/issues"
21+
22+
[project.scripts]
23+
telegram-logger-client = "telegram_logger_client.__main__:main"

telegram_logger_client/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .telegram_logger_client import TelegramLoggerClient

telegram_logger_client/__main__.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import argparse
2+
import json
3+
import os
4+
import sys
5+
import logging
6+
from .telegram_logger_client import TelegramLoggerClient
7+
8+
9+
def setup_logging(debug=False):
10+
log_level = logging.DEBUG if debug else logging.INFO
11+
logging.basicConfig(
12+
level=log_level,
13+
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
14+
datefmt="%Y-%m-%d %H:%M:%S",
15+
)
16+
logger = logging.getLogger(__name__)
17+
logger.debug(f"Logging level set to: {logging.getLevelName(log_level)}")
18+
return logger
19+
20+
21+
def main():
22+
parser = argparse.ArgumentParser(description="Send logs to telegram-logger service")
23+
parser.add_argument("--debug", action="store_true", help="Enable debug logging")
24+
parser.add_argument("--base-url", help="Base URL of the telegram-logger service")
25+
parser.add_argument("--x-id", help="X-ID token for authentication")
26+
parser.add_argument(
27+
"--caller", required=True, help="Name of the calling application or service"
28+
)
29+
parser.add_argument(
30+
"--level", required=True, choices=["info", "warning", "error"], help="Log level"
31+
)
32+
parser.add_argument("--message", required=True, help="Log message")
33+
parser.add_argument("--error", help="Error message or description")
34+
parser.add_argument("--request-id", help="Request ID for tracing")
35+
parser.add_argument("--trace-id", help="Trace ID for distributed tracing")
36+
parser.add_argument("--span-id", help="Span ID for distributed tracing")
37+
parser.add_argument(
38+
"--data", type=json.loads, help="Additional data as JSON string"
39+
)
40+
41+
args = parser.parse_args()
42+
logger = setup_logging(args.debug)
43+
44+
logger.debug(f"Parsed arguments: {args}")
45+
46+
# Get base_url and x_id from environment variables or command-line arguments
47+
base_url = args.base_url or os.environ.get("TELEGRAM_LOGGER_BASE_URL")
48+
x_id = args.x_id or os.environ.get("TELEGRAM_LOGGER_X_ID")
49+
50+
logger.debug(f"Base URL: {base_url}")
51+
logger.debug(
52+
f"X-ID: {'*' * len(x_id) if x_id else None}"
53+
) # Mask the actual X-ID for security
54+
55+
if not base_url:
56+
logger.error(
57+
"Base URL is required. Set TELEGRAM_LOGGER_BASE_URL environment variable or use --base-url argument."
58+
)
59+
sys.exit(1)
60+
61+
if not x_id:
62+
logger.error(
63+
"X-ID is required. Set TELEGRAM_LOGGER_X_ID environment variable or use --x-id argument."
64+
)
65+
sys.exit(1)
66+
67+
client = TelegramLoggerClient(base_url, x_id)
68+
logger.debug("TelegramLoggerClient initialized")
69+
70+
try:
71+
logger.debug("Attempting to send log")
72+
response = client.send_log(
73+
caller=args.caller,
74+
level=args.level,
75+
message=args.message,
76+
error=args.error,
77+
request_id=args.request_id,
78+
trace_id=args.trace_id,
79+
span_id=args.span_id,
80+
data=args.data,
81+
)
82+
logger.debug(f"Log sent successfully. Status code: {response.status_code}")
83+
except Exception as e:
84+
logger.error(f"Error sending log: {e}")
85+
sys.exit(1)
86+
87+
88+
if __name__ == "__main__":
89+
main()
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import json
2+
import requests
3+
import datetime
4+
from typing import Any, Dict, Optional
5+
6+
7+
class TelegramLoggerClient:
8+
def __init__(self, base_url: str, x_id: str):
9+
self.base_url = base_url
10+
self.x_id = x_id
11+
12+
def send_log(
13+
self,
14+
caller: str,
15+
level: str,
16+
message: str,
17+
error: Optional[str] = None,
18+
request_id: Optional[str] = None,
19+
trace_id: Optional[str] = None,
20+
span_id: Optional[str] = None,
21+
data: Optional[Dict[str, Any]] = None,
22+
) -> requests.Response:
23+
payload = {
24+
"caller": caller,
25+
"time": datetime.datetime.now().isoformat(),
26+
"level": level,
27+
"message": message,
28+
"error": error,
29+
"requestID": request_id,
30+
"traceID": trace_id,
31+
"spanID": span_id,
32+
"data": data or {},
33+
}
34+
35+
headers = {"Content-Type": "application/json", "X-ID": self.x_id}
36+
37+
response = requests.post(
38+
self.base_url, headers=headers, data=json.dumps(payload)
39+
)
40+
response.raise_for_status()
41+
return response

0 commit comments

Comments
 (0)