节点在线、应用在线、配置在线使用令牌查询
|
# 星尘监控 Python SDK
适用于 Python 3.7+,æä¾›æ˜Ÿå°˜ APM 监控和é…ç½®ä¸å¿ƒçš„æŽ¥å…¥èƒ½åŠ›ã€‚
## 功能特性
- **APM 监控**:自动追踪应用性能,记录调用链ã€é”™è¯¯ã€æ€§èƒ½æŒ‡æ ‡
- **自动埋点**:默认开å¯ï¼Œè‡ªåЍ采集 Web å…¥å£ã€å‡ºç«™ HTTPã€æ•°æ®åº“与 Redis 调用
- **链路上下文**:éµå¾ª W3C `traceparent`,å¯ä¸Ž .NET åŠå…¶å®ƒè¯è¨€ SDK 互通
- **é…ç½®ä¸å¿ƒ**:从星尘é…ç½®ä¸å¿ƒæ‹‰å–é…置,支æŒåЍæ€åˆ·æ–°
- **ç®€å•æ˜“用**ï¼šå‡ è¡Œä»£ç å³å¯æŽ¥å…¥ï¼Œæ”¯æŒè£…饰器和上下文管ç†å™¨
- **Web 框架集æˆ**:自动识别 Flask/Django/Starletteï¼Œå¦æä¾› WSGI/ASGI ä¸é—´ä»¶
## 安装
```bash
pip install newlifex-stardust
```
或直接从æºç 安装:
```bash
cd SDK/Python
pip install -e .
```
## 快速开始
### 一行接入(推è)
```python
from stardust_sdk import init
client = init("http://star.example.com:6600", "MyApp", "MySecret")
# 自动å¯ç”¨ APMã€è‡ªåŠ¨åŸ‹ç‚¹å’Œé…ç½®ä¸å¿ƒ
```
### 1. 基础使用(APM + é…置)
```python
from stardust_sdk import StardustClient
# åˆ›å»ºå®¢æˆ·ç«¯ï¼ˆåŒæ—¶å¯ç”¨ APM å’Œé…ç½®ä¸å¿ƒï¼‰
client = StardustClient(
server="http://star.example.com:6600",
app_id="MyApp",
secret="MySecret",
scope="dev" # é…置作用域:dev/test/prod
)
# å¯åŠ¨å®¢æˆ·ç«¯
client.start()
# 使用 APM 监控
with client.new_span("业务æ“作") as span:
span.tag = "傿•°ä¿¡æ¯"
do_something()
# 使用é…ç½®ä¸å¿ƒ
db_host = client.get_config("database.host", "localhost")
db_port = client.get_config_int("database.port", 3306)
debug_mode = client.get_config_bool("debug", False)
# 监å¬é…ç½®å˜æ›´
def on_config_changed(configs):
print(f"é…置已更新: {configs}")
client.on_config_change(on_config_changed)
# 程åºé€€å‡ºæ—¶åœæ¢
client.stop()
```
### 2. 仅使用 APM 监控
```python
from stardust_sdk import StardustTracer
tracer = StardustTracer(
server="http://star.example.com:6600",
app_id="MyApp",
secret="MySecret"
)
tracer.start()
# 手动埋点
with tracer.new_span("业务æ“作A") as span:
span.tag = "傿•°ä¿¡æ¯"
do_something()
# 使用装饰器
@tracer.trace("æ•°æ®åº“查询")
def query_users():
pass
tracer.stop()
```
### 3. 仅使用é…ç½®ä¸å¿ƒ
```python
from stardust_sdk import ConfigClient
config = ConfigClient(
server="http://star.example.com:6600",
app_id="MyApp",
secret="MySecret",
scope="prod"
)
config.start()
# 获å–é…ç½®
api_url = config.get("api.url", "http://localhost:8080")
timeout = config.get_int("api.timeout", 30)
# 监å¬é…ç½®å˜æ›´
config.on_change(lambda cfg: print(f"é…置更新: {cfg}"))
config.stop()
```
## 自动埋点(默认开å¯ï¼‰
创建 `StardustClient` / `StardustTracer` æ—¶è‡ªåŠ¨å®‰è£…ï¼Œæ— éœ€ä¿®æ”¹ä¸šåŠ¡ä»£ç 。
### 支æŒçš„æ¡†æž¶ä¸Žåº“
| 类型 | 自动识别/æ”¯æŒ | Span åç§° | 说明 |
|------|---------------|-----------|------|
| 出站 HTTP | `requests`ã€`urllib` | `METHOD host/path` | Tag 为完整 URL,4xx/5xx 与网络异常记为错误 |
| Web å…¥å£ | Flask(`Flask.wsgi_app`)ã€Django(`BaseHandler.get_response`)ã€Starlette(`Starlette.__call__`) | `METHOD path` | 读å–入站 `traceparent`,5xx/异常记为错误 |
| Web å…¥å£ï¼ˆæ˜¾å¼ï¼‰ | `StardustWSGIMiddleware`ã€`StardustASGIMiddleware` | `METHOD path` | æ¡†æž¶åœ¨å®‰è£…ä¹‹åŽæ‰å¯¼å…¥æ—¶ä½¿ç”¨ |
| æ•°æ®åº“ | DB-API:`sqlite3`ã€`pymysql`ã€`psycopg2` | `db:{system}:{action}:{tables}` | Tag 为 SQL 文本,自动识别表å并去除日期分表åŽç¼€ |
| Redis | `redis.Redis.execute_command`ï¼ˆåŒæ¥å®¢æˆ·ç«¯ï¼‰ | `redis:{COMMAND}` | Tag ä¸ºå‚æ•°æ‘˜è¦ |
### 链路上下文
å…¥ç«™è¯·æ±‚è¯»å–æ ‡å‡† W3C 头,å¤ç”¨ä¸Šæ¸¸ TraceId 并将上游 SpanId 作为父 Span:
```text
traceparent: 00-<32ä½åå…进制trace-id>-<16ä½åå…进制span-id>-01
```
- 兼容 .NET 历å²å®žçŽ°ï¼šå…¥ç«™ TraceId å¯ä»¥çŸäºŽ 32 ä½ï¼Œå‡ºç«™ç»Ÿä¸€ç”Ÿæˆ/输出 32 ä½ã€‚
- 出站请求若已显å¼è®¾ç½® `traceparent`,SDK ä¸è¦†ç›–。
- 星尘æœåŠ¡ç«¯è‡ªèº«æŽ¥å£ï¼ˆ`/App/`ã€`/Trace/`)ä¸ä¼šåˆ›å»º Span,也ä¸ä¼šæ³¨å…¥ `traceparent`。
### 关闿ˆ–釿–°å¯ç”¨
```python
# 创建时关é—
client = StardustClient(..., auto_instrument=False)
# è¿è¡Œæ—¶å¸è½½ / 釿–°å®‰è£…
client.uninstrument()
client.instrument()
# 使用 StardustTracer 时
tracer = StardustTracer(..., auto_instrument=False)
tracer.instrument()
```
### æ˜¾å¼ Web ä¸é—´ä»¶
若框架是在 SDK å®‰è£…ä¹‹åŽæ‰å¯¼å…¥ï¼ˆè‡ªåŠ¨è¯†åˆ«ä¸ä¼šç”Ÿæ•ˆï¼‰ï¼Œä½¿ç”¨ä¸é—´ä»¶æŽ¥å…¥ï¼š
```python
from stardust_sdk import StardustWSGIMiddleware, StardustASGIMiddleware
# WSGI(Flask 实例本身就是 WSGI 应用)
app.wsgi_app = StardustWSGIMiddleware(app.wsgi_app)
# ASGI(Starlette/FastAPI)
app = StardustASGIMiddleware(app)
```
åŒä¸€è¯·æ±‚åªä¼šäº§ç”Ÿä¸€ä¸ªå…¥å£ Span:显å¼ä¸é—´ä»¶ä¸Žæ¡†æž¶è‡ªåŠ¨åŸ‹ç‚¹é€šè¿‡è¯·æ±‚æ ‡è®°åŽ»é‡ã€‚
### é™åˆ¶
- 自动识别åªé’ˆå¯¹**安装时已导入**çš„ Web 框架;之åŽå¯¼å…¥çš„æ¡†æž¶è¯·ä½¿ç”¨æ˜¾å¼ä¸é—´ä»¶ã€‚
- è‡ªåŠ¨åŸ‹ç‚¹åœ¨æž„é€ æ—¶æ‰§è¡Œä¸€æ¬¡ï¼›ä¹‹åŽæ‰å®‰è£…/å¯¼å…¥çš„åº“éœ€é‡æ–°è°ƒç”¨ `instrument()`。
- 已通过 `from ... import connect/urlopen` æå‰ç»‘定的函数引用ä¸ä¼šè¢«æ›¿æ¢ã€‚
- Redis ä»…è¦†ç›–åŒæ¥å®¢æˆ·ç«¯ `redis.Redis`,异æ¥å®¢æˆ·ç«¯éœ€æ‰‹åŠ¨åŸ‹ç‚¹ã€‚
- æ•°æ®åº“仅覆盖 DB-API 驱动层,ä¸ç†è§£ ORM è¯ä¹‰ï¼›SQL 表å为å¯å‘å¼è§£æžã€‚
- WSGI çš„ Span 在应用返回è¿ä»£å™¨æ—¶ç»“æŸï¼Œæµå¼å“åº”çš„å®žé™…ä¼ è¾“æ—¶é—´ä¸è®¡å…¥è€—时。
- 上下文基于 `contextvars`,新建线程ä¸ä¼šè‡ªåŠ¨ç»§æ‰¿å½“å‰ Span。
- SDK ä¸åšå¤´éƒ¨é‡‡æ ·ï¼Œå‡ºç«™ç»Ÿä¸€å†™ `flags=01`ï¼Œæœ€ç»ˆé‡‡æ ·ç”±æ˜Ÿå°˜æœåŠ¡ç«¯å†³å®šã€‚
## Web 框架集æˆ
> å·²å¯ç”¨è‡ªåŠ¨åŸ‹ç‚¹ï¼ˆé»˜è®¤ï¼‰æ—¶ï¼ŒFlask/Django/Starlette æ— éœ€å†å†™ä¸‹é¢çš„æ‰‹åЍä¸é—´ä»¶ï¼›ç¤ºä¾‹ä¿ç•™ç”¨äºŽè‡ªå®šä¹‰éœ€æ±‚,或在 `auto_instrument=False` 时手工接入。
### Django ä¸é—´ä»¶
```python
# middleware.py
from stardust_sdk import StardustClient
# 全局åˆå§‹åŒ–
client = StardustClient(
"http://star.example.com:6600",
"MyDjangoApp",
"secret",
scope="prod"
)
client.start()
class StardustMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
name = f"{request.method} {request.path}"
with client.new_span(name) as span:
span.tag = request.get_full_path()
try:
response = self.get_response(request)
if response.status_code >= 400:
span.set_error(f"HTTP {response.status_code}")
return response
except Exception as ex:
span.set_error(ex)
raise
# settings.py
MIDDLEWARE = [
'myapp.middleware.StardustMiddleware',
# ... å…¶ä»–ä¸é—´ä»¶
]
# 使用é…ç½®
from myapp.middleware import client
DEBUG = client.get_config_bool("debug", False)
DATABASE_HOST = client.get_config("database.host", "localhost")
```
### Flask 集æˆ
```python
from flask import Flask, request, g
from stardust_sdk import StardustClient
app = Flask(__name__)
# 创建客户端
client = StardustClient(
"http://star.example.com:6600",
"MyFlaskApp",
"secret",
scope="prod"
)
client.start()
@app.before_request
def before_request():
name = f"{request.method} {request.path}"
span = client.new_span(name)
span.tag = request.full_path
g.stardust_span = span
@app.after_request
def after_request(response):
span = g.pop("stardust_span", None)
if span:
if response.status_code >= 400:
span.set_error(f"HTTP {response.status_code}")
span.finish()
return response
# 使用é…ç½®
app.config["DEBUG"] = client.get_config_bool("debug", False)
app.config["SECRET_KEY"] = client.get_config("secret_key")
if __name__ == "__main__":
app.run()
```
## API å‚考
### StardustClient
ç»Ÿä¸€å®¢æˆ·ç«¯ï¼ŒåŒæ—¶æä¾› APM å’Œé…置功能。
```python
client = StardustClient(
server="http://star.example.com:6600",
app_id="MyApp",
secret="MySecret",
client_id=None, # å¯é€‰ï¼Œé»˜è®¤ä¸º IP@PID
scope="", # é…置作用域
enable_trace=True, # 是å¦å¯ç”¨ APM
enable_config=True, # 是å¦å¯ç”¨é…ç½®
auto_instrument=True, # 是å¦å¯ç”¨è‡ªåŠ¨åŸ‹ç‚¹ï¼ˆé»˜è®¤å¼€å¯ï¼‰
)
```
**APM 方法**:
- `new_span(name, parent_id="", trace_id=None)` - 创建追踪片段
- `trace(name)` - 追踪装饰器
- `instrument()` / `uninstrument()` - 安装/å¸è½½è‡ªåŠ¨åŸ‹ç‚¹
- `current_span` - 当剿´»åЍ Span
- `tracer` - 获å–追踪器实例
**é…置方法**:
- `get_config(key, default="")` - 获å–å—符串é…ç½®
- `get_config_int(key, default=0)` - èŽ·å–æ•´åž‹é…ç½®
- `get_config_bool(key, default=False)` - 获å–布尔é…ç½®
- `get_all_configs()` - èŽ·å–æ‰€æœ‰é…ç½®
- `on_config_change(callback)` - 监å¬é…ç½®å˜æ›´
- `config` - 获å–é…置客户端实例
- `config_version` - 获å–当å‰é…置版本
### StardustTracer
APM 监控追踪器。
**方法**:
- `start()` - å¯åŠ¨è¿½è¸ªå™¨ï¼ˆç™»å½•ä¸ŽåŽå°ä¸ŠæŠ¥ï¼‰
- `stop()` - åœæ¢è¿½è¸ªå™¨
- `new_span(name, parent_id="", trace_id=None)` - 创建追踪片段
- `trace(name)` - 装饰器
- `instrument()` / `uninstrument()` - 安装/å¸è½½è‡ªåŠ¨åŸ‹ç‚¹
**属性**:
- `current_span` - 当剿´»åЍ Span
- `period` - 上报周期(秒)
- `max_samples` - æœ€å¤§é‡‡æ ·æ•°
- `max_errors` - æœ€å¤§é”™è¯¯é‡‡æ ·æ•°
### ConfigClient
é…ç½®ä¸å¿ƒå®¢æˆ·ç«¯ã€‚
**方法**:
- `start()` - å¯åŠ¨å®¢æˆ·ç«¯
- `stop()` - åœæ¢å®¢æˆ·ç«¯
- `get(key, default="")` - 获å–é…ç½®
- `get_int(key, default=0)` - èŽ·å–æ•´åž‹é…ç½®
- `get_bool(key, default=False)` - 获å–布尔é…ç½®
- `get_all()` - èŽ·å–æ‰€æœ‰é…ç½®
- `on_change(callback)` - æ³¨å†Œå˜æ›´å›žè°ƒ
**属性**:
- `version` - 当å‰é…置版本
- `next_version` - 下一个版本
- `refresh_interval` - 刷新间隔(秒)
## 许å¯è¯
MIT License
## 相关链接
- [星尘监控文档](https://newlifex.com/blood/stardust_monitor)
- [GitHub 仓库](https://github.com/NewLifeX/Stardust)
- [在线演示](http://star.newlifex.com)
|