sentry-logger 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.
@@ -0,0 +1,124 @@
1
+ Metadata-Version: 2.4
2
+ Name: sentry-logger
3
+ Version: 0.1.0
4
+ Summary: Push logs from your Python app to the Sentry dashboard — AI-powered service health monitoring
5
+ Author-email: Sentry <support@sentrylabs.live>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://sentrylabs.live
8
+ Project-URL: Repository, https://github.com/moiz-frost/sentry
9
+ Project-URL: Bug Tracker, https://github.com/moiz-frost/sentry/issues
10
+ Keywords: logging,monitoring,observability,sentry,dashboard,devtools
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Software Development :: Libraries
20
+ Classifier: Topic :: System :: Logging
21
+ Classifier: Topic :: System :: Monitoring
22
+ Requires-Python: >=3.9
23
+ Description-Content-Type: text/markdown
24
+
25
+ # Sentry Logger SDK (Python)
26
+
27
+ Push logs from your Python app to the Sentry dashboard.
28
+
29
+ ## Installation
30
+
31
+ ```bash
32
+ pip install sentry-logger
33
+ # or from the repo:
34
+ pip install ./sdk/python
35
+ ```
36
+
37
+ ## Quick Start — CLI + Browser OAuth
38
+
39
+ ```bash
40
+ sentry-logger init --app-name "my-service" --dsn "http://localhost:9000"
41
+ ```
42
+
43
+ What happens:
44
+
45
+ 1. CLI requests a device session from the backend
46
+ 2. Browser opens your sign-in page
47
+ 3. Sign in with Google — your app is registered and an API key is created
48
+ 4. CLI polls and stores credentials in `~/.sentry_logger/config.json`
49
+
50
+ Check the currently linked app:
51
+
52
+ ```bash
53
+ sentry-logger status
54
+ ```
55
+
56
+ ## SDK Usage
57
+
58
+ ```python
59
+ from sentry_logger import init
60
+
61
+ # Reads api_key and dsn from ~/.sentry_logger/config.json
62
+ init()
63
+
64
+ import logging
65
+ logging.info("Hello from my app")
66
+ logging.error("Something went wrong")
67
+ ```
68
+
69
+ Explicit configuration:
70
+
71
+ ```python
72
+ from sentry_logger import init
73
+
74
+ init(
75
+ api_key="sk_...",
76
+ dsn="http://localhost:9000", # your backend URL
77
+ )
78
+ ```
79
+
80
+ ## Environment Variables
81
+
82
+ | Variable | Default | Description |
83
+ |--------------------|--------------------------|--------------------------------|
84
+ | `LOGSENTRY_URL` | `http://localhost:9000` | Backend ingest URL base |
85
+
86
+ ## FastAPI Example
87
+
88
+ ```python
89
+ import logging
90
+ from fastapi import FastAPI
91
+ from sentry_logger import init
92
+
93
+ app = FastAPI()
94
+
95
+ @app.on_event("startup")
96
+ def setup_logging() -> None:
97
+ init()
98
+ logging.getLogger(__name__).info("Sentry SDK initialized")
99
+ ```
100
+
101
+ ## Configuration Reference
102
+
103
+ | Parameter | Default | Description |
104
+ |--------------------------|---------|-------------------------------------------------------|
105
+ | `api_key` | — | API key (`sk_...`). If omitted, loaded from CLI config |
106
+ | `dsn` | — | Ingest URL. Falls back to `LOGSENTRY_URL` env or `http://localhost:8001` |
107
+ | `batch_size` | `50` | Send logs when buffer reaches this size |
108
+ | `flush_interval_seconds` | `5.0` | Auto-flush buffer after this many seconds |
109
+
110
+ ## Log Format
111
+
112
+ The SDK formats logs in the standard Python logging format. The backend parses:
113
+
114
+ ```
115
+ 2024-01-01 10:00:00,123 [INFO] [ServiceName]: Log message here
116
+ ```
117
+
118
+ The `ServiceName` in brackets is used to group logs by service in the dashboard.
119
+ Use Python logger names to map to service names:
120
+
121
+ ```python
122
+ logger = logging.getLogger("PaymentService")
123
+ logger.info("Payment processed")
124
+ ```
@@ -0,0 +1,100 @@
1
+ # Sentry Logger SDK (Python)
2
+
3
+ Push logs from your Python app to the Sentry dashboard.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install sentry-logger
9
+ # or from the repo:
10
+ pip install ./sdk/python
11
+ ```
12
+
13
+ ## Quick Start — CLI + Browser OAuth
14
+
15
+ ```bash
16
+ sentry-logger init --app-name "my-service" --dsn "http://localhost:9000"
17
+ ```
18
+
19
+ What happens:
20
+
21
+ 1. CLI requests a device session from the backend
22
+ 2. Browser opens your sign-in page
23
+ 3. Sign in with Google — your app is registered and an API key is created
24
+ 4. CLI polls and stores credentials in `~/.sentry_logger/config.json`
25
+
26
+ Check the currently linked app:
27
+
28
+ ```bash
29
+ sentry-logger status
30
+ ```
31
+
32
+ ## SDK Usage
33
+
34
+ ```python
35
+ from sentry_logger import init
36
+
37
+ # Reads api_key and dsn from ~/.sentry_logger/config.json
38
+ init()
39
+
40
+ import logging
41
+ logging.info("Hello from my app")
42
+ logging.error("Something went wrong")
43
+ ```
44
+
45
+ Explicit configuration:
46
+
47
+ ```python
48
+ from sentry_logger import init
49
+
50
+ init(
51
+ api_key="sk_...",
52
+ dsn="http://localhost:9000", # your backend URL
53
+ )
54
+ ```
55
+
56
+ ## Environment Variables
57
+
58
+ | Variable | Default | Description |
59
+ |--------------------|--------------------------|--------------------------------|
60
+ | `LOGSENTRY_URL` | `http://localhost:9000` | Backend ingest URL base |
61
+
62
+ ## FastAPI Example
63
+
64
+ ```python
65
+ import logging
66
+ from fastapi import FastAPI
67
+ from sentry_logger import init
68
+
69
+ app = FastAPI()
70
+
71
+ @app.on_event("startup")
72
+ def setup_logging() -> None:
73
+ init()
74
+ logging.getLogger(__name__).info("Sentry SDK initialized")
75
+ ```
76
+
77
+ ## Configuration Reference
78
+
79
+ | Parameter | Default | Description |
80
+ |--------------------------|---------|-------------------------------------------------------|
81
+ | `api_key` | — | API key (`sk_...`). If omitted, loaded from CLI config |
82
+ | `dsn` | — | Ingest URL. Falls back to `LOGSENTRY_URL` env or `http://localhost:8001` |
83
+ | `batch_size` | `50` | Send logs when buffer reaches this size |
84
+ | `flush_interval_seconds` | `5.0` | Auto-flush buffer after this many seconds |
85
+
86
+ ## Log Format
87
+
88
+ The SDK formats logs in the standard Python logging format. The backend parses:
89
+
90
+ ```
91
+ 2024-01-01 10:00:00,123 [INFO] [ServiceName]: Log message here
92
+ ```
93
+
94
+ The `ServiceName` in brackets is used to group logs by service in the dashboard.
95
+ Use Python logger names to map to service names:
96
+
97
+ ```python
98
+ logger = logging.getLogger("PaymentService")
99
+ logger.info("Payment processed")
100
+ ```
@@ -0,0 +1,38 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "sentry-logger"
7
+ version = "0.1.0"
8
+ description = "Push logs from your Python app to the Sentry dashboard — AI-powered service health monitoring"
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = "MIT"
12
+ authors = [{ name = "Sentry", email = "support@sentrylabs.live" }]
13
+ keywords = ["logging", "monitoring", "observability", "sentry", "dashboard", "devtools"]
14
+ classifiers = [
15
+ "Development Status :: 3 - Alpha",
16
+ "Intended Audience :: Developers",
17
+ "Programming Language :: Python :: 3",
18
+ "Programming Language :: Python :: 3.9",
19
+ "Programming Language :: Python :: 3.10",
20
+ "Programming Language :: Python :: 3.11",
21
+ "Programming Language :: Python :: 3.12",
22
+ "Programming Language :: Python :: 3.13",
23
+ "Topic :: Software Development :: Libraries",
24
+ "Topic :: System :: Logging",
25
+ "Topic :: System :: Monitoring",
26
+ ]
27
+
28
+ [project.urls]
29
+ Homepage = "https://sentrylabs.live"
30
+ Repository = "https://github.com/moiz-frost/sentry"
31
+ "Bug Tracker" = "https://github.com/moiz-frost/sentry/issues"
32
+
33
+ [project.scripts]
34
+ sentry-logger = "sentry_logger.cli:main"
35
+
36
+ [tool.setuptools.packages.find]
37
+ where = ["."]
38
+ include = ["sentry_logger*"]
@@ -0,0 +1,70 @@
1
+ """
2
+ Sentry Logger SDK - Push logs from your Python app to the Sentry dashboard.
3
+ """
4
+ from __future__ import annotations
5
+
6
+ from typing import Optional
7
+
8
+ from .handler import SentryLogHandler
9
+ from .config import SentryLoggerConfig
10
+ from .local_config import load_local_config, resolve_dsn
11
+
12
+ __all__ = ["SentryLogHandler", "SentryLoggerConfig", "init"]
13
+
14
+
15
+ def init(
16
+ api_key: Optional[str] = None,
17
+ dsn: Optional[str] = None,
18
+ batch_size: int = 50,
19
+ flush_interval_seconds: float = 5.0,
20
+ ) -> SentryLogHandler:
21
+ """
22
+ Initialize Sentry Logger and attach it to the root Python logger.
23
+
24
+ Args:
25
+ api_key: Your Sentry API key. If omitted, reads from the local config
26
+ file written by ``sentry-logger init`` (~/.sentry_logger/config.json).
27
+ dsn: Backend base URL. If omitted, uses the production endpoint
28
+ (https://api.sentrylabs.live) or the value saved by the CLI.
29
+ Can also be overridden with the SENTRY_INGEST_URL env var.
30
+ batch_size: Logs to buffer before flushing (default 50).
31
+ flush_interval_seconds: Seconds between automatic flushes (default 5).
32
+
33
+ Returns:
34
+ SentryLogHandler — attach to specific loggers if needed.
35
+
36
+ Example (CLI-linked app, zero config):
37
+ >>> from sentry_logger import init
38
+ >>> init()
39
+
40
+ Example (explicit key):
41
+ >>> from sentry_logger import init
42
+ >>> init(api_key="sk_...")
43
+ """
44
+ import logging
45
+
46
+ resolved_dsn = resolve_dsn(dsn)
47
+
48
+ if not api_key:
49
+ cfg = load_local_config()
50
+ api_key = cfg.get("api_key")
51
+ # Also prefer the DSN saved by the CLI if not provided explicitly
52
+ if not dsn and cfg.get("dsn"):
53
+ resolved_dsn = str(cfg["dsn"]).rstrip("/")
54
+
55
+ if not api_key:
56
+ raise ValueError(
57
+ "api_key is required. Either run `sentry-logger init` first, "
58
+ "or pass api_key= to init()."
59
+ )
60
+
61
+ config = SentryLoggerConfig(
62
+ api_key=api_key,
63
+ batch_size=batch_size,
64
+ flush_interval_seconds=flush_interval_seconds,
65
+ _backend_url=resolved_dsn,
66
+ )
67
+ handler = SentryLogHandler(config)
68
+ logging.getLogger().addHandler(handler)
69
+ logging.getLogger().setLevel(logging.INFO)
70
+ return handler
@@ -0,0 +1,150 @@
1
+ """CLI for one-command SDK onboarding."""
2
+ from __future__ import annotations
3
+
4
+ import argparse
5
+ import json
6
+ import sys
7
+ import time
8
+ from typing import Optional
9
+ import urllib.error
10
+ import urllib.parse
11
+ import urllib.request
12
+ import webbrowser
13
+
14
+ from .local_config import DEFAULT_DSN, get_default_config_path, load_local_config, save_local_config
15
+
16
+
17
+ def _http_json(method: str, url: str, payload: Optional[dict] = None) -> dict:
18
+ data = json.dumps(payload).encode("utf-8") if payload is not None else None
19
+ request = urllib.request.Request(
20
+ url,
21
+ method=method,
22
+ data=data,
23
+ headers={"Content-Type": "application/json"},
24
+ )
25
+ with urllib.request.urlopen(request, timeout=15) as response:
26
+ body = response.read().decode("utf-8")
27
+ return json.loads(body) if body else {}
28
+
29
+
30
+ def cmd_init(args: argparse.Namespace) -> int:
31
+ dsn = args.dsn.rstrip("/")
32
+ try:
33
+ start = _http_json(
34
+ "POST",
35
+ f"{dsn}/sdk/device/start",
36
+ {
37
+ "app_name": args.app_name,
38
+ "description": args.description,
39
+ "ttl_seconds": args.ttl_seconds,
40
+ },
41
+ )
42
+ except urllib.error.HTTPError as exc:
43
+ print(f"Failed to start login flow: HTTP {exc.code}", file=sys.stderr)
44
+ return 1
45
+ except Exception as exc:
46
+ print(f"Failed to start login flow: {type(exc).__name__}", file=sys.stderr)
47
+ return 1
48
+
49
+ verification_uri_complete = start["verification_uri_complete"]
50
+ user_code = start["user_code"]
51
+ device_code = start["device_code"]
52
+ interval = int(start.get("interval", 3))
53
+
54
+ print("Open this URL to login and link your app:")
55
+ print(verification_uri_complete)
56
+ print(f"If prompted, enter code: {user_code}")
57
+
58
+ if not args.no_browser:
59
+ webbrowser.open(verification_uri_complete)
60
+
61
+ started = time.monotonic()
62
+ while True:
63
+ if (time.monotonic() - started) > args.timeout_seconds:
64
+ print("Timed out waiting for approval.", file=sys.stderr)
65
+ return 2
66
+
67
+ try:
68
+ poll_url = f"{dsn}/sdk/device/poll?{urllib.parse.urlencode({'device_code': device_code})}"
69
+ poll = _http_json("GET", poll_url)
70
+ except urllib.error.HTTPError as exc:
71
+ if exc.code == 400:
72
+ print("Device code expired. Run init again.", file=sys.stderr)
73
+ return 2
74
+ time.sleep(interval)
75
+ continue
76
+ except Exception:
77
+ time.sleep(interval)
78
+ continue
79
+
80
+ if poll.get("status") == "approved":
81
+ payload = {
82
+ "app_id": poll["app_id"],
83
+ "app_name": poll.get("app_name", args.app_name),
84
+ "api_key": poll["api_key"],
85
+ "dsn": poll.get("dsn", dsn),
86
+ }
87
+ saved = save_local_config(payload, path=args.config_path)
88
+ print("")
89
+ print(f"Linked app '{payload['app_name']}' ({payload['app_id']}).")
90
+ print(f"Credentials saved to {saved}.")
91
+ print("Use in code:")
92
+ print(" from sentry_logger import init")
93
+ print(" init() # reads local config")
94
+ return 0
95
+
96
+ time.sleep(interval)
97
+
98
+
99
+ def cmd_status(args: argparse.Namespace) -> int:
100
+ cfg = load_local_config(path=args.config_path)
101
+ if not cfg:
102
+ print(f"No config found at {args.config_path or get_default_config_path()}")
103
+ return 1
104
+ print(f"App: {cfg.get('app_name')}")
105
+ print(f"App ID: {cfg.get('app_id')}")
106
+ print(f"DSN: {cfg.get('dsn')}")
107
+ print(f"API key present: {'yes' if cfg.get('api_key') else 'no'}")
108
+ return 0
109
+
110
+
111
+ def build_parser() -> argparse.ArgumentParser:
112
+ parser = argparse.ArgumentParser(prog="sentry-logger", description="Sentry Logger SDK CLI")
113
+ sub = parser.add_subparsers(dest="command", required=True)
114
+
115
+ _dsn_help = f"Backend base URL (default: {DEFAULT_DSN})"
116
+
117
+ init_parser = sub.add_parser("init", help="Login in browser and provision app credentials")
118
+ init_parser.add_argument("--app-name", required=True, help="Name for the app to register")
119
+ init_parser.add_argument("--description", default="", help="Optional app description")
120
+ init_parser.add_argument("--dsn", default=DEFAULT_DSN, help=_dsn_help)
121
+ init_parser.add_argument("--ttl-seconds", type=int, default=600, help="Login session TTL")
122
+ init_parser.add_argument("--timeout-seconds", type=int, default=300, help="Polling timeout")
123
+ init_parser.add_argument("--no-browser", action="store_true", help="Do not auto-open browser")
124
+ init_parser.add_argument("--config-path", default=None, help="Override config file path")
125
+ init_parser.set_defaults(func=cmd_init)
126
+
127
+ login_parser = sub.add_parser("login", help="Alias for init")
128
+ login_parser.add_argument("--app-name", required=True, help="Name for the app to register")
129
+ login_parser.add_argument("--description", default="", help="Optional app description")
130
+ login_parser.add_argument("--dsn", default=DEFAULT_DSN, help=_dsn_help)
131
+ login_parser.add_argument("--ttl-seconds", type=int, default=600, help="Login session TTL")
132
+ login_parser.add_argument("--timeout-seconds", type=int, default=300, help="Polling timeout")
133
+ login_parser.add_argument("--no-browser", action="store_true", help="Do not auto-open browser")
134
+ login_parser.add_argument("--config-path", default=None, help="Override config file path")
135
+ login_parser.set_defaults(func=cmd_init)
136
+
137
+ status_parser = sub.add_parser("status", help="Show current local SDK config")
138
+ status_parser.add_argument("--config-path", default=None, help="Override config file path")
139
+ status_parser.set_defaults(func=cmd_status)
140
+ return parser
141
+
142
+
143
+ def main() -> int:
144
+ parser = build_parser()
145
+ args = parser.parse_args()
146
+ return int(args.func(args))
147
+
148
+
149
+ if __name__ == "__main__":
150
+ raise SystemExit(main())
@@ -0,0 +1,25 @@
1
+ """Configuration for Sentry Logger SDK."""
2
+ from __future__ import annotations
3
+
4
+ import os
5
+ from dataclasses import dataclass, field
6
+ from typing import Optional
7
+
8
+
9
+ @dataclass
10
+ class SentryLoggerConfig:
11
+ api_key: str
12
+ batch_size: int = 50
13
+ flush_interval_seconds: float = 5.0
14
+
15
+ # Internal - URL is set via environment variable or resolved from local config
16
+ _backend_url: Optional[str] = field(default=None, repr=False)
17
+
18
+ def __post_init__(self):
19
+ if not self._backend_url:
20
+ self._backend_url = os.environ.get(
21
+ "SENTRY_INGEST_URL",
22
+ "https://api.sentrylabs.live",
23
+ )
24
+ self._backend_url = self._backend_url.rstrip("/")
25
+ self.ingest_url = f"{self._backend_url}/ingest"
@@ -0,0 +1,73 @@
1
+ """
2
+ Logging handler that buffers log records and sends them in batches to the Sentry ingest API.
3
+ """
4
+ import atexit
5
+ import json
6
+ import logging
7
+ import threading
8
+ import time
9
+ import urllib.request
10
+
11
+ from .config import SentryLoggerConfig
12
+
13
+
14
+ class SentryLogHandler(logging.Handler):
15
+ """
16
+ Buffers log records and POSTs them in batches to the Sentry ingest endpoint.
17
+ Uses a background thread for non-blocking sends.
18
+ """
19
+
20
+ def __init__(self, config: SentryLoggerConfig):
21
+ super().__init__()
22
+ self.config = config
23
+ self._buffer: list[str] = []
24
+ self._lock = threading.Lock()
25
+ self._shutdown = False
26
+ self._last_flush = time.monotonic()
27
+ self.setFormatter(
28
+ logging.Formatter("%(asctime)s [%(levelname)s] [%(name)s]: %(message)s")
29
+ )
30
+ atexit.register(self.flush)
31
+
32
+ def emit(self, record: logging.LogRecord) -> None:
33
+ try:
34
+ msg = self.format(record)
35
+ with self._lock:
36
+ self._buffer.append(msg)
37
+ now = time.monotonic()
38
+ if (
39
+ len(self._buffer) >= self.config.batch_size
40
+ or (now - self._last_flush) >= self.config.flush_interval_seconds
41
+ ):
42
+ self._flush_locked()
43
+ except Exception:
44
+ self.handleError(record)
45
+
46
+ def _flush_locked(self) -> None:
47
+ if not self._buffer:
48
+ return
49
+ logs = self._buffer[:]
50
+ self._buffer = []
51
+ self._last_flush = time.monotonic()
52
+ threading.Thread(target=self._send, args=(logs,), daemon=True).start()
53
+
54
+ def _send(self, logs: list[str]) -> None:
55
+ try:
56
+ body = json.dumps({"logs": logs}).encode("utf-8")
57
+ req = urllib.request.Request(
58
+ self.config.ingest_url,
59
+ data=body,
60
+ method="POST",
61
+ headers={
62
+ "Content-Type": "application/json",
63
+ "Authorization": f"Bearer {self.config.api_key}",
64
+ "X-API-Key": self.config.api_key,
65
+ },
66
+ )
67
+ urllib.request.urlopen(req, timeout=10)
68
+ except Exception:
69
+ pass # Fail silently to avoid disrupting the app
70
+
71
+ def flush(self) -> None:
72
+ with self._lock:
73
+ self._flush_locked()
@@ -0,0 +1,51 @@
1
+ """Local CLI config persistence for SDK credentials."""
2
+ from __future__ import annotations
3
+
4
+ import json
5
+ import os
6
+ from pathlib import Path
7
+ from typing import Any, Optional
8
+
9
+
10
+ def get_default_config_path() -> Path:
11
+ home = Path.home()
12
+ return home / ".sentry_logger" / "config.json"
13
+
14
+
15
+ def ensure_parent(path: Path) -> None:
16
+ path.parent.mkdir(parents=True, exist_ok=True)
17
+
18
+
19
+ def load_local_config(path: Optional[str] = None) -> dict[str, Any]:
20
+ config_path = Path(path) if path else get_default_config_path()
21
+ if not config_path.exists():
22
+ return {}
23
+ try:
24
+ with config_path.open("r", encoding="utf-8") as f:
25
+ payload = json.load(f)
26
+ return payload if isinstance(payload, dict) else {}
27
+ except Exception:
28
+ return {}
29
+
30
+
31
+ def save_local_config(payload: dict[str, Any], path: Optional[str] = None) -> Path:
32
+ config_path = Path(path) if path else get_default_config_path()
33
+ ensure_parent(config_path)
34
+ with config_path.open("w", encoding="utf-8") as f:
35
+ json.dump(payload, f, indent=2)
36
+ return config_path
37
+
38
+
39
+ DEFAULT_DSN = "https://api.sentrylabs.live"
40
+
41
+
42
+ def resolve_dsn(explicit_dsn: Optional[str] = None) -> str:
43
+ if explicit_dsn:
44
+ return explicit_dsn.rstrip("/")
45
+ env_dsn = os.environ.get("SENTRY_INGEST_URL")
46
+ if env_dsn:
47
+ return env_dsn.rstrip("/")
48
+ cfg = load_local_config()
49
+ if cfg.get("dsn"):
50
+ return str(cfg["dsn"]).rstrip("/")
51
+ return DEFAULT_DSN
@@ -0,0 +1,124 @@
1
+ Metadata-Version: 2.4
2
+ Name: sentry-logger
3
+ Version: 0.1.0
4
+ Summary: Push logs from your Python app to the Sentry dashboard — AI-powered service health monitoring
5
+ Author-email: Sentry <support@sentrylabs.live>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://sentrylabs.live
8
+ Project-URL: Repository, https://github.com/moiz-frost/sentry
9
+ Project-URL: Bug Tracker, https://github.com/moiz-frost/sentry/issues
10
+ Keywords: logging,monitoring,observability,sentry,dashboard,devtools
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Software Development :: Libraries
20
+ Classifier: Topic :: System :: Logging
21
+ Classifier: Topic :: System :: Monitoring
22
+ Requires-Python: >=3.9
23
+ Description-Content-Type: text/markdown
24
+
25
+ # Sentry Logger SDK (Python)
26
+
27
+ Push logs from your Python app to the Sentry dashboard.
28
+
29
+ ## Installation
30
+
31
+ ```bash
32
+ pip install sentry-logger
33
+ # or from the repo:
34
+ pip install ./sdk/python
35
+ ```
36
+
37
+ ## Quick Start — CLI + Browser OAuth
38
+
39
+ ```bash
40
+ sentry-logger init --app-name "my-service" --dsn "http://localhost:9000"
41
+ ```
42
+
43
+ What happens:
44
+
45
+ 1. CLI requests a device session from the backend
46
+ 2. Browser opens your sign-in page
47
+ 3. Sign in with Google — your app is registered and an API key is created
48
+ 4. CLI polls and stores credentials in `~/.sentry_logger/config.json`
49
+
50
+ Check the currently linked app:
51
+
52
+ ```bash
53
+ sentry-logger status
54
+ ```
55
+
56
+ ## SDK Usage
57
+
58
+ ```python
59
+ from sentry_logger import init
60
+
61
+ # Reads api_key and dsn from ~/.sentry_logger/config.json
62
+ init()
63
+
64
+ import logging
65
+ logging.info("Hello from my app")
66
+ logging.error("Something went wrong")
67
+ ```
68
+
69
+ Explicit configuration:
70
+
71
+ ```python
72
+ from sentry_logger import init
73
+
74
+ init(
75
+ api_key="sk_...",
76
+ dsn="http://localhost:9000", # your backend URL
77
+ )
78
+ ```
79
+
80
+ ## Environment Variables
81
+
82
+ | Variable | Default | Description |
83
+ |--------------------|--------------------------|--------------------------------|
84
+ | `LOGSENTRY_URL` | `http://localhost:9000` | Backend ingest URL base |
85
+
86
+ ## FastAPI Example
87
+
88
+ ```python
89
+ import logging
90
+ from fastapi import FastAPI
91
+ from sentry_logger import init
92
+
93
+ app = FastAPI()
94
+
95
+ @app.on_event("startup")
96
+ def setup_logging() -> None:
97
+ init()
98
+ logging.getLogger(__name__).info("Sentry SDK initialized")
99
+ ```
100
+
101
+ ## Configuration Reference
102
+
103
+ | Parameter | Default | Description |
104
+ |--------------------------|---------|-------------------------------------------------------|
105
+ | `api_key` | — | API key (`sk_...`). If omitted, loaded from CLI config |
106
+ | `dsn` | — | Ingest URL. Falls back to `LOGSENTRY_URL` env or `http://localhost:8001` |
107
+ | `batch_size` | `50` | Send logs when buffer reaches this size |
108
+ | `flush_interval_seconds` | `5.0` | Auto-flush buffer after this many seconds |
109
+
110
+ ## Log Format
111
+
112
+ The SDK formats logs in the standard Python logging format. The backend parses:
113
+
114
+ ```
115
+ 2024-01-01 10:00:00,123 [INFO] [ServiceName]: Log message here
116
+ ```
117
+
118
+ The `ServiceName` in brackets is used to group logs by service in the dashboard.
119
+ Use Python logger names to map to service names:
120
+
121
+ ```python
122
+ logger = logging.getLogger("PaymentService")
123
+ logger.info("Payment processed")
124
+ ```
@@ -0,0 +1,12 @@
1
+ README.md
2
+ pyproject.toml
3
+ sentry_logger/__init__.py
4
+ sentry_logger/cli.py
5
+ sentry_logger/config.py
6
+ sentry_logger/handler.py
7
+ sentry_logger/local_config.py
8
+ sentry_logger.egg-info/PKG-INFO
9
+ sentry_logger.egg-info/SOURCES.txt
10
+ sentry_logger.egg-info/dependency_links.txt
11
+ sentry_logger.egg-info/entry_points.txt
12
+ sentry_logger.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ sentry-logger = sentry_logger.cli:main
@@ -0,0 +1 @@
1
+ sentry_logger
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+