Metadata-Version: 2.4
Name: iboxpay-xlog
Version: 0.1.0
Summary: iboxpay 通用日志框架：基于 Loguru 的统一格式、分文件路由与脱敏能力
Author: renruiquan
License: MIT
Project-URL: Homepage, https://pypi.org/project/iboxpay-xlog/
Project-URL: Issues, https://pypi.org/project/iboxpay-xlog/
Keywords: logging,loguru,iboxpay,structured-logging,redaction
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: System :: Logging
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: loguru>=0.7.3
Provides-Extra: dev
Requires-Dist: build>=1.2.2; extra == "dev"
Requires-Dist: pytest>=8.3.0; extra == "dev"
Requires-Dist: pytest-cov>=6.0.0; extra == "dev"
Requires-Dist: twine>=5.1.0; extra == "dev"
Requires-Dist: ruff>=0.6.0; extra == "dev"
Dynamic: license-file

# iboxpay-xlog

> iboxpay 通用日志框架：基于 [Loguru](https://github.com/Delgan/loguru) 的统一格式、分文件路由与脱敏能力。

`iboxpay-xlog` 把 iboxpay 后端服务里反复用到的日志规范沉淀为一个可复用的库，让所有 Python 服务在同一套约定下输出日志：

- 类 Logback 文本格式：`[time] [thread] [level] [name] [transactionId] [spanId] [timeDiff] [serviceId] [protocol] [logType] - message`
- 标准库 `logging` 与 Loguru 自动桥接，第三方库（uvicorn、httpx 等）的输出与业务日志统一格式
- 默认 5 类文件 sink：`app` / `interface` / `access` / `error` / `remote`，按 logger 名称自动路由
- 文件按 100MB 或小时维度滚动，可关闭或调整阈值
- 内置身份证、银行卡脱敏，并避免误伤大陆手机号
- 完全 dataclass 化的 `LoggingSettings`，无侵入接入任何项目

---

## 安装

```bash
pip install iboxpay-xlog
```

依赖：`loguru>=0.7.3`，Python `>=3.10`。

## 快速开始

```python
from iboxpay_xlog import configure_logging, get_logger

configure_logging()

log = get_logger(__name__)
log.info("service started")

remote_log = get_logger("remote").bind(
    protocol="http",
    logType="remote",
    serviceId="sms-gateway",
)
remote_log.info("sms request finished")
```

默认行为：

- 控制台输出（`stdout`，INFO 级别）
- 文件输出到当前工作目录下的 `logs/`，子目录分别为 `app/` `interface/` `access/` `error/` `remote/`

## 自定义配置

```python
from pathlib import Path

from iboxpay_xlog import LoggingSettings, configure_logging

configure_logging(
    LoggingSettings(
        service_name="iboxpay-foo",
        log_base_dir=Path("/var/log/iboxpay-foo"),
        console_level="DEBUG",
        rotation_max_bytes=200 * 1024 * 1024,
        rotate_hourly=False,
    )
)
```

也可以通过环境变量切换日志根目录。例如 `service_name="iboxpay-foo"` 会自动认环境变量 `IBOXPAY_FOO_LOG_BASE_DIR`：

```bash
export IBOXPAY_FOO_LOG_BASE_DIR=/data/logs/foo
```

需要完全自定义文件 sink 时，传入 `LogSink` 元组：

```python
from iboxpay_xlog import LogSink, LoggingSettings, configure_logging

configure_logging(
    LoggingSettings(
        service_name="iboxpay-bar",
        sinks=(
            LogSink(name="app", level="INFO", exclude_logger_names=frozenset({"audit"})),
            LogSink(name="audit", level="INFO", include_logger_names=frozenset({"audit"})),
        ),
    )
)
```

仅希望输出到控制台时关闭文件输出：

```python
configure_logging(LoggingSettings(enable_file_logging=False))
```

## 脱敏

```python
from iboxpay_xlog import redact_log_text, redact_log_value

redact_log_text("user 110101199003078888 paid via 6222021234567890123")
# 'user 110101******8888 paid via 622202*********0123'

redact_log_value({"id_card": "110101199003078888", "phone": "13800138000"})
# {'id_card': '110101******8888', 'phone': '13800138000'}
```

- 身份证、银行卡保留前 6 位与后 4 位
- 11 位以 `1[3-9]` 开头的大陆手机号 **不** 脱敏

## 与标准库 logging 协同

`configure_logging()` 默认会把根 logger 的 handler 替换为内置的 `InterceptHandler`，并：

- 将 `httpx` 调整为 `WARNING` 级别（可通过 `silenced_loggers` 覆盖）
- 把 `uvicorn`、`uvicorn.error` 桥接进 Loguru
- 禁用 `uvicorn.access`，由你自行用 `get_logger("access")` 控制访问日志

如需关闭桥接：

```python
configure_logging(LoggingSettings(intercept_stdlib=False))
```

## 自动记录请求/响应报文（伴生包）

`iboxpay-xlog` 本身只做日志框架，不绑定任何 Web 框架或 HTTP 客户端。需要“开箱即用”的请求/响应自动记录，可直接安装两个伴生包：

| 包 | 作用 |
|---|---|
| [`iboxpay-xlog-fastapi`](https://pypi.org/project/iboxpay-xlog-fastapi/) | FastAPI/Starlette `HttpLoggingMiddleware`，自动记录入站请求体、响应体、`X-Request-ID`、耗时 |
| [`iboxpay-xlog-httpx`](https://pypi.org/project/iboxpay-xlog-httpx/) | httpx 事件钩子，自动把出站 HTTP 调用写入 `remote` 日志 |

```bash
pip install iboxpay-xlog iboxpay-xlog-fastapi iboxpay-xlog-httpx
```

```python
import httpx
from fastapi import FastAPI
from iboxpay_xlog import configure_logging
from iboxpay_xlog_fastapi import HttpLoggingMiddleware
from iboxpay_xlog_httpx import attach_logging

configure_logging()

app = FastAPI()
app.add_middleware(HttpLoggingMiddleware)

sms_client = attach_logging(httpx.Client(), service_id="sms-gateway")
```

## 测试

```python
from iboxpay_xlog import configure_logging, get_logger
from iboxpay_xlog.testing import capture_records

configure_logging()
with capture_records() as records:
    get_logger("demo").info("hi")

assert records[-1]["message"] == "hi"
```

## 重置 / 重新配置

```python
from iboxpay_xlog import configure_logging, reset_logging_for_tests

reset_logging_for_tests()
configure_logging(new_settings)
```

## 本地开发

```bash
pip install -e ".[dev]"
pytest
python -m build
twine check dist/*
```

## License

MIT
