Metadata-Version: 2.5
Name: ikc-log-center
Version: 2.0.30
Summary: Lightweight SDK + Server for log_center — decorator-based instrumentation with HTTP/gRPC/Celery delivery, multi-backend storage, and search UI.
Author-email: shark8848 <admin@sharky-ai.com>
License: MIT
License-File: LICENSE
Keywords: instrumentation,log-center,logging,telemetry,tracing
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.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: System :: Logging
Requires-Python: >=3.10
Requires-Dist: requests>=2.28
Provides-Extra: agent
Requires-Dist: deepagents>=0.2; extra == 'agent'
Requires-Dist: langchain-mcp-adapters>=0.1; extra == 'agent'
Requires-Dist: langchain-openai>=0.3; extra == 'agent'
Requires-Dist: mcp-server-git>=0.6; extra == 'agent'
Requires-Dist: pyyaml>=6.0; extra == 'agent'
Provides-Extra: all
Requires-Dist: celery>=5.0; extra == 'all'
Requires-Dist: cryptography>=41.0; extra == 'all'
Requires-Dist: deepagents>=0.2; extra == 'all'
Requires-Dist: fastapi>=0.100; extra == 'all'
Requires-Dist: flask>=2.0; extra == 'all'
Requires-Dist: grpcio>=1.50; extra == 'all'
Requires-Dist: langchain-mcp-adapters>=0.1; extra == 'all'
Requires-Dist: langchain-openai>=0.3; extra == 'all'
Requires-Dist: mcp-server-git>=0.6; extra == 'all'
Requires-Dist: mcp<2.0,>=1.28; extra == 'all'
Requires-Dist: mysql-connector-python>=8.0; extra == 'all'
Requires-Dist: oracledb>=2.0; extra == 'all'
Requires-Dist: pillow>=10.0; extra == 'all'
Requires-Dist: psycopg[binary]>=3.0; extra == 'all'
Requires-Dist: sqlalchemy>=2.0; extra == 'all'
Requires-Dist: starlette; extra == 'all'
Requires-Dist: uvicorn[standard]>=0.20; extra == 'all'
Provides-Extra: celery
Requires-Dist: celery>=5.0; extra == 'celery'
Provides-Extra: dev
Requires-Dist: cryptography>=41.0; extra == 'dev'
Requires-Dist: httpx>=0.24; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: ruff>=0.1; extra == 'dev'
Provides-Extra: fastapi
Requires-Dist: fastapi>=0.100; extra == 'fastapi'
Requires-Dist: starlette; extra == 'fastapi'
Provides-Extra: flask
Requires-Dist: flask>=2.0; extra == 'flask'
Provides-Extra: grpc
Requires-Dist: grpcio>=1.50; extra == 'grpc'
Provides-Extra: mcp
Requires-Dist: mcp<2.0,>=1.28; extra == 'mcp'
Provides-Extra: mysql
Requires-Dist: mysql-connector-python>=8.0; extra == 'mysql'
Provides-Extra: observation
Requires-Dist: pillow>=10.0; extra == 'observation'
Requires-Dist: playwright>=1.40; extra == 'observation'
Provides-Extra: oracle
Requires-Dist: oracledb>=2.0; extra == 'oracle'
Provides-Extra: pg
Requires-Dist: psycopg[binary]>=3.0; extra == 'pg'
Provides-Extra: server
Requires-Dist: cryptography>=41.0; extra == 'server'
Requires-Dist: fastapi>=0.100; extra == 'server'
Requires-Dist: sqlalchemy>=2.0; extra == 'server'
Requires-Dist: uvicorn[standard]>=0.20; extra == 'server'
Provides-Extra: ui
Description-Content-Type: text/markdown

<p align="center">
  <img src="ikc-log-center-banner.png" alt="IKC Log Center" width="100%" />
</p>

<p align="center">
  <strong>Lightweight SDK + Centralized Log Service + AI Agent</strong><br/>
  Auto-capture · Multi-transport · Multi-backend · MCP for AI · Built-in Agent
</p>

<p align="center">
  <a href="https://pypi.org/project/ikc-log-center/"><img src="https://img.shields.io/pypi/v/ikc-log-center" alt="PyPI" /></a>
  <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-green.svg" alt="MIT" /></a>
  <img src="https://img.shields.io/badge/Python-3.10%2B-blue" alt="Python 3.10+" />
</p>

<p align="center">
  <b>English</b> |
  <a href="README_zh.md">中文</a> |
  <a href="README_ja.md">日本語</a> |
  <a href="README_fr.md">Français</a> |
  <a href="README_de.md">Deutsch</a> |
  <a href="README_es.md">Español</a>
</p>

---

## Overview

**IKC Log Center** is a lightweight, Python-first logging platform consisting of a **Client SDK** and a **Central Server**:

- **SDK** — decorator-based auto-instrumentation with structured JSON logs, delivered via HTTP / gRPC / Celery.
- **Server** — receives, stores, and searches logs with pluggable backends (SQLite / MySQL / PostgreSQL / Elasticsearch), plus a built-in React Web UI, MCP server for AI agents, Bearer Token authentication, and an embedded **AI Agent** for intelligent log analysis.

```
App (SDK) ──HTTP/gRPC/Celery──▶ Log Center Server ──▶ SQLite / MySQL / PG / ES
                                       │
                 ┌─────────────────────┼─────────────────────┐
                 │                     │                     │
              Web UI              AI Agent             MCP Server
           (React SPA)          (LangGraph)        (stdio / SSE)
                 │                     │                     │
           Token Auth            Work Modes         External AI Tools
                         auto / plan / approval     Claude Code · Codex
                                                   Cursor · Windsurf
                                       │
                              ┌────────┴────────┐
                              │                 │
                         Git Repos        Business DBs
                        (read-only)      MySQL · PG · Oracle
```

## Features

| Category | Highlights |
|----------|-----------|
| Auto-capture | `@instrumented` decorator — duration, status, args logging with slow-call detection |
| Multi-transport | HTTP POST, gRPC unary, Celery task — combinable via env var |
| Multi-backend | SQLite (zero-config), MySQL, PostgreSQL, Elasticsearch |
| Trace analysis | Distributed trace_id / span_id propagation across FastAPI, Flask, Celery |
| Web UI | React-based search, dashboard, trace chain visualization, token management |
| Encrypted phone search | Keywords containing a phone number also match its Java-AESUtil-compatible AES-128-CBC ciphertext, so encrypted and plaintext logs are both found |
| Task Center | Scheduled tasks (cron / interval / once) with Task/Run lifecycle, retry, live SSE stream |
| Observation Center | Prometheus-style multi-page monitoring: periodic screenshots (Playwright/http probes), structured + vision anomaly detection (independent `LOG_CENTER_VISION_*` model), runbook (tool+skill) remediation with chat-thread plan confirmation & approval-mode step gating |
| MCP for AI | Expose log search as MCP tools — compatible with Claude Code, Codex, Cursor, Windsurf & more |
| AI Agent | Built-in LangGraph agent — log analysis, Git repo reading, DB queries, artifact generation |
| Auth | OpenAI-style `sk-lc-*` Bearer tokens with SHA-256 hash storage |
| Ops-friendly | Rotating file logs, 7-day retention, shell scripts, CLI tools |

## Installation

```bash
# Client SDK only
pip install ikc-log-center                        # HTTP delivery (default)
pip install ikc-log-center[grpc]                  # + gRPC delivery
pip install ikc-log-center[celery]                # + Celery delivery
pip install ikc-log-center[fastapi]               # + FastAPI middleware
pip install ikc-log-center[flask]                 # + Flask hooks

# Server
pip install ikc-log-center[server]                # HTTP server + SQLite
pip install ikc-log-center[mcp]                   # + MCP server
pip install ikc-log-center[agent]                 # + AI Agent (LangGraph)
pip install ikc-log-center[server,mysql]          # + MySQL backend
pip install ikc-log-center[server,pg]             # + PostgreSQL backend

# Everything
pip install ikc-log-center[all]
```

### Install from repository wheel archive (`release/`)

每个已发布版本都把 wheel/sdist 归档在仓库 `release/`（见「Release（发布契约）」），
可直接用归档 wheel 安装，适合固定版本、离线或内网环境：

```bash
# 方式一：克隆仓库后本地安装（推荐，最可靠，extras 完整）
git clone git@github.com:shark8848/ikc-log-center.git
cd ikc-log-center
pip install "./release/ikc_log_center-1.4.19-py3-none-any.whl[all]"

# 方式二：GitHub raw 直装（仅当仓库对该网络公开可访问时可用）
pip install "ikc-log-center[all] @ https://raw.githubusercontent.com/shark8848/ikc-log-center/main/release/ikc_log_center-1.4.19-py3-none-any.whl"

# 方式三：tiancloud（GitLab 风格 raw URL，私有仓库需带鉴权）
pip install "ikc-log-center[all] @ https://code.tiancloud.com/sunhy/ikc-log-center/-/raw/main/release/ikc_log_center-1.4.19-py3-none-any.whl"
```

> `release/` 目录与发布脚本 `scripts/publish-pypi.sh` 同步维护：每次发布自动归档并推送所有远程仓库；
> 具体版本号以 `release/README.md` 清单为准。raw 直装依赖远程仓库对该网络公开可访问；内网/私有仓库请用方式一。

### Upgrade (升级)

- 容器热升级（不重建镜像，wheel + 前端 bundle）：`./scripts/hot-upgrade-container.sh --version 2.0.15`
- 镜像重建 / 启动（含沙箱）：`./deploy_scripts/deploy_log_center.sh --start --sandbox`
- docker.io 不可达时用本地缓存基础镜像构建：
  `LC_PYTHON_BASE_IMAGE=python:3.12-slim ./deploy_scripts/deploy_log_center.sh --start --sandbox --no-push`
- PyPI 发布（对外契约）：`LOG_CENTER_VERSION=2.0.15 ./scripts/publish-pypi.sh`
- 沙箱要求：容器需挂载 `-v /var/run/docker.sock:/var/run/docker.sock`（部署脚本 `--sandbox`）；
  容器重建会丢失热升级内容，重建后必须重新执行热升级脚本。
- 详细见 [docs/deployment.md §14.5 版本升级](docs/deployment.md)。

### Docker Deployment (optional bundled HAProxy)

```bash
# Standard build & start (host network, external ports stay 9315/9316/9318)
./deploy_scripts/deploy_log_center.sh --start

# Bundle HAProxy reverse proxy into the image and enable it automatically
# (frontend ports remain 9315/9316/9318)
./deploy_scripts/deploy_log_center.sh --haproxy --start

# Manual build
docker build -f docker/Dockerfile -t ikc/log-center:latest .
docker build -f docker/Dockerfile --build-arg INCLUDE_HAPROXY=true -t ikc/log-center:haproxy .

# Direct `docker run` — enable the bundled HAProxy
# (front 9315/9316/9318 → backend 19315/19316/19318, Web UI prefix stripped)
docker run -d --name ikc-log-center \
  --restart unless-stopped \
  --network host \
  -v $(pwd)/data:/app/data \
  -v $(pwd)/logs:/app/logs \
  -e HA_PROXY_ENABLED=true \
  -e HA_PROXY_WEB_PREFIX=/ikc-log-center \
  ikc/log-center:latest \
  "log-center-mcp --transport http --host 0.0.0.0 --port 19318 & exec log-center-server --port 19315 --ui --agent --grpc"
```

See [docs/deployment.md §8 Docker Deployment](docs/deployment.md) for details.

> **Web UI path prefix:** production portals often require the Web UI to be served
> under a path prefix such as `https://xxxxxx:9135/ikc-log-center/`. The frontend
> build is **prefix-adaptive by default** (relative assets + runtime prefix
> detection in `web/src/basePath.ts`), so the same `web/dist` works for every
> combination of HAProxy / non-HAProxy × prefixed / non-prefixed — no rebuild is
> needed. HAProxy strips the prefix before forwarding, or set
> `LOG_CENTER_WEB_PREFIX=/ikc-log-center` for the backend to serve it natively.
> `VITE_BASE_PATH` is still honored for explicitly baking a prefix (legacy). See
> [docs/deployment.md §8.10](docs/deployment.md) for details.

> **Troubleshooting (legacy baked-prefix builds only):** builds made with
> `VITE_BASE_PATH=/ikc-log-center/` must be reached through a prefix-stripping
> proxy or a backend that understands the prefix. Hitting the backend directly
> (uvicorn, no HAProxy, no `LOG_CENTER_WEB_PREFIX`) at `/ikc-log-center` only serves
> `index.html` — assets/API under the prefix are SPA-fallbacked to `index.html`
> (HTTP 200, `text/html`), which makes the page fail to load. Fixes: set
> `LOG_CENTER_WEB_PREFIX=/ikc-log-center` on the backend, put a stripping proxy in
> front, or rebuild with `VITE_BASE_PATH=/` for root-path access.

## Quick Start

### 1. Start the Server

```bash
# HTTP API on :9315 (SQLite storage, zero config)
log-center-server

# With gRPC (:9316) and Web UI
log-center-server --grpc --ui

# Or use shell scripts
./start-log-center.sh
./show-log-center.sh
./stop-log-center.sh
```

### 2. Instrument Your App

```python
from log_center_sdk import configure, instrumented

configure(module_name="my_app")

@instrumented("process_order", slow_threshold_ms=500)
def process_order(order_id: str, amount: float):
    ...

@instrumented("llm_call", log_args={"model"}, redact_args={"api_key"})
async def call_llm(prompt: str, model: str, api_key: str):
    ...
```

Enable remote delivery:

```bash
LOG_CENTER_ENABLE=true \
LOG_CENTER_URL=http://localhost:9315 \
python my_app.py
```

### 3. Framework Integrations

**FastAPI:**
```python
from log_center_sdk.integrations.fastapi import TraceMiddleware
app.add_middleware(TraceMiddleware)
```

**Flask:**
```python
from log_center_sdk.integrations.flask import init_trace_hooks
init_trace_hooks(app)
```

**Celery Workers:**
```python
from log_center_sdk import patch_celery_app
patch_celery_app(app)  # auto-reinit handlers after fork
```

## Delivery Modes

| Mode | Protocol | Port | Best For |
|------|----------|------|----------|
| `api` | HTTP POST JSON | 9315 | Cross-network, external apps |
| `grpc` | gRPC unary JSON bytes | 9316 | Low-latency internal network |
| `celery` | Redis queue + send_task | 6379 | Apps with existing Celery |

Combine modes: `LOG_CENTER_DELIVERY=grpc,api`

## MCP Server (AI Agent Ready)

Expose log search capabilities as MCP tools. Works with the built-in AI Agent **and** any external MCP-compatible tool:

```bash
pip install ikc-log-center[mcp]
log-center-mcp
```

### External Tool Integration

Connect your favorite AI dev tools to Log Center via MCP:

**Claude Code / Codex CLI** (`~/.claude/mcp.json` or `mcp_servers.json`):
```json
{
  "mcpServers": {
    "log-center": {
      "command": "log-center-mcp",
      "env": {
        "LOG_CENTER_URL": "http://localhost:9315",
        "LOG_CENTER_TOKEN": "sk-lc-xxxxx"
      }
    }
  }
}
```

**Cursor / Windsurf** (Settings → MCP Servers):
```json
{
  "log-center": {
    "command": "log-center-mcp",
    "env": {
      "LOG_CENTER_URL": "http://localhost:9315"
    }
  }
}
```

Once connected, you can ask your AI assistant:
- *"Search for ERROR logs in the last hour"*
- *"Find all logs for trace_id abc-123"*
- *"Show slow calls (>500ms) from module payment"*

## AI Agent

Built-in intelligent assistant powered by LangGraph, capable of log analysis, Git repository reading, database queries, **external Elasticsearch log analysis**, artifact generation, and **parallel sub-agent delegation**.

```bash
pip install ikc-log-center[agent]
log-center-server --agent
```

### Capabilities

| Capability | Description |
|------------|-------------|
| Log analysis | Search and analyze logs via MCP tools (search, stats, trace chain, levels) |
| Git repos | Clone & read repositories (read-only, write ops blocked) |
| Database queries | MySQL / PostgreSQL / Oracle — forced read-only |
| External ES clusters | Register external Elasticsearch clusters to read-only search/analyze other systems' own logs |
| Artifacts | Generate downloadable files (reports, analysis, code, etc.) |
| Work modes | `auto` (tools run automatically), `plan` (generate plan then execute), `approval` (human-in-the-loop) |
| Memory | Conversation memory with auto-extraction of key facts |
| Session history | Persistent per-thread conversation history with resume support |
| Context compression | `window` / `token_limit` / `summarize` strategies to manage long conversations |
| Sub-agent delegation | Spawn parallel sub-agents for complex multi-node tasks (e.g., analyze each node independently) |
| Dynamic tool routing | Classify user intent per turn and inject only relevant tools (reduces ~45% token cost) |
| Docker sandbox | Isolated code execution in Docker containers with network isolation and resource limits |
| Skills | Runtime-loadable skill packages (SKILL.md) — prompt injection, declared-tool routing, and `skill.py` executors |
| Multi-language UI | Full Chinese / English internationalization for the Agent chat interface |

### Model & Non-Standard Params (模型与 LLM 非标参数配置)

The chat model (`model_config`) and the vision model (`vision_config`, used for observation screenshot analysis)
accept non-standard OpenAI-compatible request params via `extra_body`. Params are merged into the **top-level**
of the request body, so anything your gateway/provider supports (e.g. `enable_moderation`, `user`, `metadata`)
works without code changes.

- Environment (defaults): set JSON in
  `LOG_CENTER_AGENT_EXTRA_BODY` (chat model) or `LOG_CENTER_VISION_EXTRA_BODY` (vision model), e.g.
  `LOG_CENTER_AGENT_EXTRA_BODY='{"enable_moderation": true}'`.
- UI: Agent chat → 配置 (Settings) drawer — “非标请求参数（JSON）” field for both models.
  Leave empty to keep unchanged; type `{}` to clear; otherwise the JSON object fully replaces the current params.
- REST: `PUT /api/agent/config` with
  `{"model_config": {"extra_body": {"enable_moderation": true}}}` (or `vision_config`).

Secrets in `extra_body` (keys hinting `token`/`key`/`secret`/`password`/`authorization`) are masked in
`GET /api/agent/config` responses and restored automatically when the masked value is echoed back on update.
Config changes trigger an automatic agent rebuild, so they take effect immediately (vision requests use the
settings at capture-analysis time).

### Observation Center Manual (观测中心配置手册)

- [docs/observation-runbook-manual.md](docs/observation-runbook-manual.md) — 观测目标绑定技能/剧本、
  Runbook（处置剧本）YAML 编排、处置方案由指定技能生成（`plan_skill`）、审批执行与排错。

### Sub-Agent Delegation

When enabled, the main agent gains a `task` tool to spawn ephemeral sub-agents:

```
User: "Analyze errors on each node separately"
  Main Agent → get_services() → [nodeA, nodeB, nodeC]
  Main Agent → task("Analyze nodeA", type="log-analyst")  ─┐
             → task("Analyze nodeB", type="log-analyst")  ─┼─ parallel
             → task("Analyze nodeC", type="log-analyst")  ─┘
  Main Agent ← collect results → generate summary report
```

Built-in sub-agent types:
- **log-analyst** — specialized in per-node/per-service log & trace analysis
- **report-writer** — generates structured analysis reports and saves artifacts
- **general-purpose** — inherits all tools for any complex multi-step task

### Docker Sandbox

When enabled, Agent file operations and command execution run inside isolated Docker containers:

```bash
# Local testing (host machine)
LOG_CENTER_AGENT_SANDBOX_ENABLED=true log-center-server --port 9315 --agent

# Docker deployment (DooD mode)
./deploy_scripts/deploy_log_center.sh --start --sandbox
```

Sandbox security features: `--network=none` (no network), `--memory` limits, `--rm` (auto-cleanup), `/tmp` tmpfs.

### Dynamic Tool Routing

When enabled, each user message is classified by a lightweight LLM call into tool groups (`log`, `git`, `repo`, `db`, `es`, `artifact`), and only the matching subset is injected — reducing per-turn token cost by ~45% without losing capability.

> **Safety**: Git write operations (commit, push, add, reset), all database write operations (INSERT, UPDATE, DELETE, DDL), and write/delete/reindex on external ES clusters are strictly blocked.

### Skills (Skill 管理 + 运行时加载)

Skills are reusable capability packages loaded at runtime from `data/skills/` (configurable via `LOG_CENTER_AGENT_SKILLS_DIR`). Each skill is a directory with a required `SKILL.md` (YAML frontmatter + Markdown body) and an optional `skill.py` executor:

```
data/skills/
└── <skill_name>/
    ├── SKILL.md          # required — YAML frontmatter + Markdown instructions
    ├── scripts/          # optional — executable code (Agent Skills spec)
    ├── references/       # optional — documentation (Agent Skills spec)
    ├── assets/           # optional — static resources (Agent Skills spec)
    └── skill.py          # optional — platform executor run(ctx) -> str
```

Skill packages are validated 100% against the [Agent Skills spec](https://agentskills.io/specification)
(frontmatter `name` must equal the directory name; `description` is required;
the Markdown body is the instructions). Official frontmatter fields:

- `name` — required, 1-64 chars, lowercase letters/digits/hyphens, no leading/trailing
  or consecutive hyphens, must equal the parent directory name
- `description` — required, 1-1024 chars, describes what the skill does and when to use it
- `license` — optional license name or bundled license file reference
- `compatibility` — optional environment requirements (≤500 chars)
- `metadata` — optional string→string key-value mapping
- `allowed-tools` — optional space-separated pre-approved tools

```yaml
---
name: daily-log-review
description: 每日日志巡检：统计错误、发现新错误模式、生成报告
license: MIT
metadata:
  version: "1.0.0"
# ── Platform extensions (not part of the Agent Skills spec) ──
when_to_use: 用户要求日志巡检、日报、错误趋势分析时使用
tools: [search_logs, get_log_stats, get_trace_chain, save_artifact]
---
# Daily Log Review

执行每日日志巡检时，按以下步骤进行：…
```

Three capability mechanisms:
- **A · Prompt injection** — the Markdown body (instructions) + `when_to_use` are injected into the agent system prompt.
- **B · Tool orchestration** — declared `tools` / `allowed-tools` join the `skill` routing group for dynamic tool routing.
- **C · Executor** — `skill.py`'s `run(ctx)` is registered as a langchain tool `skill_<name>`; `ctx` receives `{"messages": [...]}`.

Platform extensions (not part of the spec, used by the A/B/C mechanisms above):
`version`, `enabled`, `when_to_use`, `tools`, `aliases`, and the legacy
frontmatter `instructions` field (fallback only when the body is empty).

Management API (all runtime, no restart required):
- `GET /api/agent/skills` — list installed skills with enabled state
- `PUT /api/agent/skills/{name}` — enable/disable (persisted to `data/skills/.state.json`, agent rebuilt)
- `POST /api/agent/skills` — upload `<name>.md` or `<name>.zip`; rejected with a 400
  spec-violation reason when the package does not conform (name rules, name ≠ directory
  name, missing/too-long description, invalid frontmatter); zip entries checked for path traversal
- `GET /api/agent/skills/{name}/export` — download a skill package as `<name>.zip` (SKILL.md + skill.py + assets/, excluding `__pycache__`/`*.pyc`)
- `DELETE /api/agent/skills/{name}` — permanently delete a skill (directory + state, tombstoned so default templates don't auto-reseed)

MCP resources `log-center://skills` and `log-center://skills/{name}` expose installed skills to external MCP clients. Two example skills (`daily-log-review`, `error-cluster-analysis`) are bundled and auto-seeded on first run.

**禁用/删除后的对话一致性**：禁用（或删除）的技能会从 Agent 的系统提示词、工具注册与路由分类中移除；
历史对话记忆里残留的「技能已安装」等旧事实也会被过滤（匹配技能名与 `SKILL.md` frontmatter 的 `aliases`），
因此对话中不会再出现/生效已禁用的技能。

**对话式删除**：删除技能必须在对话中由用户明确说出技能名后执行——Agent 通过 `delete_skill` 工具删除；
若用户未提供技能名，Agent 会先询问，禁止猜测或未经确认删除。

> **Safety**: a skill's `skill.py` executor runs as arbitrary code on the server — only install skills from trusted sources; a sandboxed executor is planned (see `docs/iteration-guidance.md` §2).

## Release（发布契约）

每次发布走 `scripts/publish-pypi.sh`，流程固定为：

1. 构建 wheel + sdist（`python -m build`）；
2. twine 上传 PyPI；
3. **归档**：构建产物按版本复制到 `release/`（如 `release/ikc_log_center-1.4.19-py3-none-any.whl`）；
4. **推送**：`git commit` 归档并 push 到**所有**远程仓库（origin / tiancloud 等）。

第 3/4 步是仓库硬契约（`AGENTS.md` / `process.md`），默认强制执行；仅在例外场景用
`--no-repo-release` 豁免并须在 `process.md` 会话记录写明原因。`release/README.md` 维护已归档版本清单。

## Authentication

OpenAI-style Bearer Token auth. Tokens (`sk-lc-<48 hex>`) are stored as SHA-256 hashes; plaintext is shown only once at creation.

```bash
# Generate a token
log-center-server --gen-token "production server"

# List / revoke tokens
log-center-server --list-tokens
log-center-server --revoke-token "sk-lc-a1b2"

# Start server with auth enabled
LOG_CENTER_AUTH_ENABLED=true log-center-server --ui
```

Client SDK carries the token:

```bash
LOG_CENTER_TOKEN=sk-lc-xxxxx LOG_CENTER_ENABLE=true LOG_CENTER_URL=http://server:9315 python my_app.py
```

> `/health`, `/docs`, `/openapi.json` are always auth-free.

## Storage Backends

| Backend | `LOG_CENTER_STORE` | Extra Deps |
|---------|-------------------|------------|
| Local file + SQLite | `local` (default) | — |
| MySQL | `mysql` | `[mysql]` |
| PostgreSQL | `pg` | `[pg]` |
| Elasticsearch | `es` | — |

> Local file logging is **always active** regardless of backend choice.

## Time Zones

- Log `ts` values are stored **as received**; queries, the Web UI, MCP and
  Agent retrieval display them converted to the server display timezone
  (`LOG_CENTER_TZ_OFFSET`, default `8` → UTC+8 / Asia/Shanghai), e.g.
  `2026-08-30T14:14:13+08:00`.
- Convention: **naive timestamps without an offset are treated as UTC**
  (typical for SDK clients running in UTC Docker containers) and converted to
  the display timezone; aware timestamps (`Z` / `±HH:MM`) are converted
  exactly.
- The SDK (`log_center_sdk`) emits `ts` with a timezone offset since v1.4.21
  to avoid ambiguity. Date-only or unparseable values pass through unchanged.

## API Endpoints

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/ingest` | POST | Ingest single or batch JSON logs |
| `/search` | GET | Query by `trace_id` / `level` / `message_substr` / `limit` (a `message_substr` containing a CN mobile is also matched against its AES-128-CBC ciphertext) |
| `/api/tasks` | GET/POST | List / create scheduled tasks (cron / interval / once) |
| `/api/tasks/{id}/start\|pause\|resume\|terminate\|runs` | POST | Task lifecycle actions + run-now (`/runs`) |
| `/api/tasks/{id}/stream` | GET | SSE live status stream for the latest run |
| `/health` | GET | Health check (auth-free) |
| `/docs` | GET | OpenAPI docs (auth-free) |

## Environment Variables

<details>
<summary><b>Client SDK</b></summary>

| Variable | Default | Description |
|----------|---------|-------------|
| `LOG_CENTER_ENABLE` | `false` | Enable remote log delivery |
| `LOG_CENTER_DELIVERY` | `api` | Delivery mode: `api` / `grpc` / `celery` / comma-combined |
| `LOG_CENTER_URL` | — | HTTP delivery URL (e.g. `http://log-center:9315`) |
| `LOG_CENTER_GRPC_ADDR` | — | gRPC address (e.g. `log-center:9316`) |
| `LOG_CENTER_CELERY_BROKER` | `redis://localhost:6379/0` | Celery broker URL |
| `LOG_CENTER_TIMEOUT` | `2` | Delivery timeout (seconds) |
| `LOG_CENTER_QUEUE` | `1000` | In-memory queue size |
| `LOG_CENTER_BATCH` | `50` | Batch size |
| `LOG_CENTER_TOKEN` | — | Bearer token (required when server auth is on) |
| `LOG_LEVEL` | `INFO` | Log level |
| `LOG_JSON` | `true` | JSON format output |
| `LOG_FILE_PATH` | `logs/{module}.log` | Log file path |
| `LOG_FILE_MAX_MB` | `500` | Max file size (MB) |
| `LOG_FILE_BACKUP` | `3` | Rotation backup count |
| `LOG_FILE_RETENTION_DAYS` | `14` | Retention days |

</details>

<details>
<summary><b>Server</b></summary>

| Variable | Default | Description |
|----------|---------|-------------|
| `LOG_CENTER_PORT` | `9315` | HTTP API port |
| `LOG_CENTER_HOST` | `0.0.0.0` | Bind address |
| `LOG_CENTER_GRPC_PORT` | `9316` | gRPC port |
| `LOG_CENTER_STORE` | `local` | Backend: `local` / `sqlite` / `mysql` / `pg` / `es` |
| `LOG_CENTER_DB_PATH` | `data/log_center/log_center.db` | SQLite database path |
| `LOG_CENTER_AUTH_ENABLED` | `false` | Enable Bearer Token auth |
| `LOG_CENTER_MYSQL_HOST/PORT/USER/PASSWORD/DB` | — | MySQL connection |
| `LOG_CENTER_PG_HOST/PORT/USER/PASSWORD/DB` | — | PostgreSQL connection |
| `LOG_CENTER_ES_ENDPOINT` | — | Elasticsearch endpoint URL |
| `LOG_CENTER_ES_INDEX` | `log-center` | ES index name |
| `LOG_CENTER_CORS_ORIGINS` | `*` | Allowed CORS origins |
| `LOG_CENTER_FORWARD_URLS` | — | Forward target URLs (comma-separated) |
| `LOG_CENTER_TZ_OFFSET` | `8` | Display timezone offset in hours (default UTC+8 / Shanghai); e.g. `5`, `-7` |
| `LOG_CENTER_TASK_DISPATCH_INTERVAL` | `10` | Task scheduler scan interval (seconds) |
| `LOG_CENTER_OBS_INTERVAL` | `60` | Observation capture dispatch interval (seconds) |
| `LOG_CENTER_OBS_CONCURRENCY` | `4` | Max concurrent capture browser instances |
| `LOG_CENTER_OBS_DIFF_THRESHOLD` | `0.15` | Screenshot diff ratio that triggers a `diff` anomaly |
| `LOG_CENTER_OBS_DATA_DIR` | `data/observations` | Screenshot/runbook storage directory |
| `LOG_CENTER_OBS_MAX_RUNS_DAYS` | `7` | Screenshot retention (days) |
| `LOG_CENTER_OBS_PREAPPROVE_READONLY` | `true` | Pre-approve read-only runbook steps on plan confirm (write steps always require approval) |
| `LOG_CENTER_OBS_ALLOW_EXTERNAL` | `false` | Allow observing external (non-private) URLs — SSRF guard, default off |
| `OBS_CHROMIUM_EXECUTABLE` | `chromium` | Playwright browser executable path |
| `LOG_CENTER_VISION_ENABLED` | `true` | Enable multimodal vision analysis (independent of chat model) |
| `LOG_CENTER_VISION_MODEL` | `gpt-4o` | Vision model name (e.g. Qwen-VL / GLM-4V via OpenAI-compatible endpoint) |
| `LOG_CENTER_VISION_BASE_URL` / `_API_KEY` | — | Vision model endpoint & key (decoupled from `LOG_CENTER_AGENT_*`) |
| `LOG_CENTER_VISION_DETAIL` | `low` | Image detail passed to the vision model (`low` / `high`) |
| `LOG_CENTER_VISION_TIMEOUT` | `30` | Vision request timeout (seconds) |
| `LOG_CENTER_VISION_EXTRA_BODY` | `{}` | JSON of non-standard params merged into the vision request body top-level, e.g. `{"enable_moderation": true}` |
| `LOG_CENTER_AGENT_MODEL` | `gpt-4o` | Agent LLM model name |
| `LOG_CENTER_AGENT_BASE_URL` | — | LLM API base URL |
| `LOG_CENTER_AGENT_API_KEY` | — | LLM API key |
| `LOG_CENTER_AGENT_EXTRA_BODY` | `{}` | JSON of non-standard params merged into the chat request body top-level, e.g. `{"enable_moderation": true}` |
| `LOG_CENTER_AGENT_WORK_MODE` | `auto` | Agent work mode: `auto` / `plan` / `approval` |
| `LOG_CENTER_AGENT_RECURSION_LIMIT` | `1000` | Max tool-call rounds per turn |
| `LOG_CENTER_AGENT_TOOL_ROUTING` | `false` | Enable dynamic tool routing (intent-based subset injection) |
| `LOG_CENTER_AGENT_SUBAGENT` | `false` | Enable sub-agent delegation (parallel task execution) |
| `LOG_CENTER_AGENT_CONTEXT_STRATEGY` | `window` | Context compression: `none` / `window` / `token_limit` / `summarize` |
| `LOG_CENTER_AGENT_CONTEXT_MAX_MESSAGES` | `50` | Max messages to keep (window strategy) |
| `LOG_CENTER_AGENT_CONTEXT_MAX_TOKENS` | `60000` | Max tokens in context (token_limit strategy) |
| `LOG_CENTER_AGENT_ES_ENDPOINT` | — | Auto-register an external ES cluster (`es-default`) for read-only log analysis |
| `LOG_CENTER_AGENT_ES_INDEX_PATTERN` | `*` | Default index pattern (e.g. `app-*`) |
| `LOG_CENTER_AGENT_ES_USERNAME` / `_PASSWORD` | — | Basic Auth for the external ES cluster |
| `LOG_CENTER_AGENT_ES_VERIFY_SSL` | `true` | Verify SSL cert of the external ES cluster |
| `LOG_CENTER_AGENT_ES_TIME_FIELD` | `@timestamp` | Timestamp field used for time-range filters / sorting |
| `LOG_CENTER_AGENT_ES_TIMEOUT` | `10` | Request timeout (seconds) |

</details>

---

## Security

### Security Advisory — SPA Fallback Arbitrary File Disclosure (2026-08-10)

**Affected:** all versions **≤ 1.4.9** with the Web UI enabled
**Fixed in:** **v1.4.10**

A crafted URL with a leading slash (e.g. `GET //etc/passwd`) could reach the SPA fallback route with an absolute path, causing the server to serve **arbitrary files from the host** (e.g. `/etc/passwd`, `/etc/shadow`, application source code).

**Please upgrade immediately:**

```bash
# pip deployments — upgrade to the patched version
pip install --upgrade "ikc-log-center[all]==1.4.10"

# Docker deployments — rebuild & restart from the repo root
./deploy_scripts/deploy_log_center.sh --start
```

**Full report:** [docs/security/SPA-fallback-path-injection-fix-report.md](docs/security/SPA-fallback-path-injection-fix-report.md) (root cause, PoC, verification matrix, and upgrade guide).

To report a security issue, please open a GitHub issue with the `security` label or contact the maintainers directly.

---

## License

This project is licensed under the **[MIT License](https://opensource.org/licenses/MIT)**.

Copyright (c) IKC Team. You are free to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, subject to inclusion of the copyright and license notices. The software is provided "as is", without warranty of any kind.
