Metadata-Version: 2.4
Name: otel-fastapi
Version: 1.0.1
Summary: FastAPI/Flask + OpenTelemetry integration for easy tracing and logging
Author: Your Name
License: MIT
Project-URL: Homepage, https://github.com/yourname/otel-fastapi
Project-URL: Repository, https://github.com/yourname/otel-fastapi.git
Project-URL: Issues, https://github.com/yourname/otel-fastapi/issues
Keywords: fastapi,flask,opentelemetry,tracing,logging
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Requires-Python: >=3.8
Description-Content-Type: text/markdown
Requires-Dist: opentelemetry-api>=1.22.0
Requires-Dist: opentelemetry-sdk>=1.22.0
Requires-Dist: opentelemetry-instrumentation-requests>=0.43b0
Requires-Dist: opentelemetry-instrumentation-urllib3>=0.43b0
Requires-Dist: opentelemetry-exporter-otlp-proto-grpc>=1.22.0
Requires-Dist: python-json-logger>=2.0.7
Provides-Extra: fastapi
Requires-Dist: fastapi>=0.109.0; extra == "fastapi"
Requires-Dist: uvicorn[standard]>=0.27.0; extra == "fastapi"
Requires-Dist: opentelemetry-instrumentation-fastapi>=0.43b0; extra == "fastapi"
Provides-Extra: flask
Requires-Dist: flask>=2.0.0; extra == "flask"
Requires-Dist: opentelemetry-instrumentation-flask>=0.43b0; extra == "flask"
Provides-Extra: all
Requires-Dist: otel-fastapi[fastapi,flask]; extra == "all"
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: httpx>=0.26.0; extra == "dev"
Requires-Dist: black; extra == "dev"
Requires-Dist: mypy; extra == "dev"
Requires-Dist: python-dotenv>=1.0.0; extra == "dev"

# otel-fastapi

FastAPI/Flask + OpenTelemetry integration for easy tracing and logging.
- **自动检测**：自动识别 FastAPI 或 Flask
- **零侵入**：业务代码不改，只需 3 行配置
- **自动关联**：logger 自动带 trace_id
- **一键安装**：pip install 即用

---

## 🚀 快速开始

### 1. 安装

```bash
# FastAPI 项目
pip install otel-fastapi[fastapi] python-dotenv

# Flask 项目
pip install otel-fastapi[flask] python-dotenv

# 全部
pip install otel-fastapi[all]
```

### 2. 配置环境变量

创建 `.env` 文件：

```env
# 服务配置
OTEL_SERVICE_NAME=my-service
OTEL_SERVICE_VERSION=1.0.0
OTEL_ENVIRONMENT=development

# OTLP Collector 地址
OTEL_EXPORTER_OTLP_ENDPOINT=http://172.26.21.103:4317

# 开关控制
OTEL_ENABLED=true
OTEL_LOGS_ENABLED=true

# 日志级别
LOG_LEVEL=INFO
```

### 3. 集成（仅需 3 行！）

#### FastAPI 项目：

```python
from fastapi import FastAPI
from dotenv import load_dotenv
load_dotenv()

from otel_fastapi import configure_logging, configure_tracing, instrument

# ⭐ 仅需这 3 行！
configure_logging()
configure_tracing()

app = FastAPI()
instrument(app)  # 自动识别 FastAPI！

# 你的业务代码（原样保留！）
import logging
logger = logging.getLogger(__name__)

@app.get("/")
async def root():
    logger.info("请求来了")  # 自动关联 trace_id！
    return {"message": "ok"}
```

#### Flask 项目：

```python
from flask import Flask
from dotenv import load_dotenv
load_dotenv()

from otel_fastapi import configure_logging, configure_tracing, instrument_flask

# ⭐ 配置 OTel
configure_logging()
configure_tracing()

app = Flask(__name__)
instrument_flask(app)  # 显式 instrument Flask

# 你的业务代码（原样保留！）
import logging
logger = logging.getLogger(__name__)

@app.route("/")
def root():
    logger.info("请求来了")  # 自动关联 trace_id！
    return {"message": "ok"}
```

---

## 📖 完整 API 使用

### 装饰器：`@span`

为函数创建 span：

```python
from otel_fastapi import span, add_event, set_attribute

@span(name="get_users_from_db")
def get_users_from_db():
    # 添加事件
    add_event("db_query_start", {"query": "SELECT * FROM users"})

    # 业务逻辑...
    time.sleep(0.1)

    # 添加属性到当前 span
    set_attribute("user.count", 10)

    add_event("db_query_end")
    return []
```

### 手动管理 span

```python
from otel_fastapi import get_tracer

tracer = get_tracer(__name__)

with tracer.start_as_current_span("slow_operation"):
    with tracer.start_as_current_span("step1_data_preparation"):
        time.sleep(0.2)
        add_event("step1_complete", {"duration_ms": 200})

    with tracer.start_as_current_span("step2_business_logic"):
        time.sleep(0.3)
```

### 获取 logger

```python
from otel_fastapi import get_logger

logger = get_logger(__name__)
logger.info("信息")
logger.warning("警告")
logger.error("错误")
```

### 所有可用导出

```python
from otel_fastapi import (
    # 配置
    configure_logging,
    configure_tracing,
    # 装饰器和工具
    span,
    add_event,
    set_attribute,
    get_tracer,
    get_logger,
    # Instrumentation
    instrument,          # 自动检测
    instrument_fastapi,  # 显式 FastAPI
    instrument_flask,    # 显式 Flask
)
```

---

## 📋 环境变量说明

| 变量名 | 默认值 | 说明 |
|--------|--------|------|
| `OTEL_SERVICE_NAME` | `fastapi-service` | 服务名称 |
| `OTEL_SERVICE_VERSION` | `1.0.0` | 服务版本 |
| `OTEL_ENVIRONMENT` | `development` | 环境 |
| `OTEL_EXPORTER_OTLP_ENDPOINT` | `http://172.26.21.103:4317` | OTLP 收集器地址 |
| `OTEL_ENABLED` | `true` | 是否启用 tracing |
| `OTEL_LOGS_ENABLED` | `true` | 是否启用日志导出 |
| `LOG_LEVEL` | `INFO` | 日志级别 |

---

## 🔍 Kibana 查询指南

### 查询模式：从 trace 找到问题，再查日志

```
# 第一步：在 traces-generic.otel-default 索引中找问题
attributes.http.route: "/v1/embeddings"
and duration > 300000000
```

```
# 第二步：复制 trace_id 到 logs-generic.otel-default 索引中查
trace_id: "abc123def456..."
```

### 按服务名查询

```
service.name: "flask-demo"
```

---

## 📂 运行示例

```bash
cd examples

# Flask 完整示例（推荐）
python test_final.py

# FastAPI 示例
python fastapi_example.py

# Flask 简单示例
python flask_example.py
```

---

## ❓ 常见问题

### Q: 业务代码需要改吗？
**不需要！** 用标准 `logger.info()`，trace_id 自动关联。

### Q: 可以只开启日志，不开 tracing 吗？
可以！设置 `OTEL_ENABLED=false` 即可。

### Q: 如何完全关闭？
设置 `OTEL_ENABLED=false` 和 `OTEL_LOGS_ENABLED=false`。

### Q: Flask 启动时配置 OTel 的最佳实践？

建议使用 `@app.before_request` + 标志位模式（如示例代码所示），确保 `get_tracer()` 在 `configure_tracing()` 之后调用：

```python
tracer = None  # 先不初始化

@app.before_request
def startup_once():
    global tracer
    if hasattr(app, 'is_initialized'):
        return
    app.is_initialized = True

    configure_logging()
    configure_tracing()
    instrument_flask(app)
    tracer = get_tracer(__name__)  # 现在可以安全获取
```

---

## 📄 许可证

MIT License
