
1. 这不是个“后台管理模板”而是一套可审计、可追溯、可告警的生产级日志中枢FastapiAdmin 不是那种装完就能跑、跑起来就不管的玩具型后台框架。我用它搭过三个中型 SaaS 系统从电商订单调度中心到医疗设备远程监控平台最后都卡在同一个地方日志。不是没有日志而是日志散、乱、缺上下文、难关联、查不到源头——用户说“昨天下午三点下单失败”你翻遍 access.log、error.log、sqlalchemy.log发现三份日志里时间戳差800毫秒、trace_id 完全不一致、数据库报错连表名都没打全。这时候你才明白FastapiAdmin 的日志体系不是锦上添花的配置项而是整个系统可观测性的地基。标题里说的“系统日志体系”指的不是简单调用 logging.basicConfig() 那一套。它是一套贯穿请求生命周期、绑定业务上下文、分层分级存储、支持结构化检索的完整链路。核心配置参数也不是 config.py 里几行注释掉的变量而是决定日志能否真正服务于运维、审计、安全、性能分析的七把钥匙LOG_LEVEL控制信息密度LOG_FORMAT决定字段可解析性LOG_FILE_SIZE影响磁盘轮转策略LOG_RETENTION_DAYS关系 GDPR 合规底线LOG_TRACE_ID_HEADER是分布式追踪的命门LOG_INCLUDE_SQL直接决定 DBA 能否定位慢查询LOG_SANITIZE_FIELDS则是 PII 数据不出库的安全红线。这七个参数我挨个在生产环境调过三轮以上每调一个都得配合同步修改 ELK 字段映射、Prometheus metrics 抓取规则、甚至审计系统的合规检查脚本。所以这篇不是教你怎么“启用日志”而是告诉你当你的 FastapiAdmin 项目要上线、要过等保、要被客户审计时这七个参数怎么设、为什么这么设、设错会出什么事故。适合谁看如果你还在用 print() 调试 admin 接口或者只把日志当成 crash 时的救命稻草那这篇可能超纲但如果你正负责一个需要 7×24 小时稳定运行、有明确审计要求、或已接入统一日志平台的 FastapiAdmin 项目那你现在打开的就是一份我在三个项目里踩坑、回滚、再验证后整理出来的“日志配置军规”。2. 日志体系设计逻辑从“记录发生了什么”到“还原整个决策链”2.1 为什么 FastapiAdmin 不直接复用 Starlette 的日志中间件Starlette 的LoggingMiddleware确实能打 request/response 基础信息但它只做两件事记录 HTTP 方法路径状态码耗时以及捕获未处理异常。问题在于FastapiAdmin 的核心价值不在 CRUD 表单而在业务动作的语义化表达。比如点击“批量导出用户数据”按钮背后触发的是权限校验RBAC 规则、数据筛选SQL WHERE 条件、文件生成内存/磁盘 IO、邮件通知SMTP 发送四个原子操作。Starlette 日志只会记下/api/export/users 200 OK而你真正需要的是“用户 admincompany.comID: 1024基于角色 ‘超级管理员’筛选条件 ‘statusactive AND created_at 2024-01-01’导出 3,247 条记录生成 Excel 文件 /tmp/export_abc123.xlsx12.4MB发送通知至 opscompany.com —— 全流程耗时 8.2s其中 DB 查询占 6.1s”。这个粒度Starlette 原生日志根本无法承载。FastapiAdmin 的日志体系本质是事件驱动架构EDA的日志化落地。它把每个 admin 操作抽象为一个AdminEvent对象包含event_type如EXPORT_START,EXPORT_SUCCESS,PERMISSION_DENIED、actor操作人 ID/角色/IP、target影响对象如UserModel(id5678)、context业务上下文如{filter: {status: active}, count: 3247}、duration_ms、trace_id。这套模型不是凭空设计的而是直接对应 ISO/IEC 27001 审计条款中对“信息系统操作日志”的五要素要求谁、何时、何地、做了什么、结果如何。我见过太多团队在等保测评时被卡在日志字段缺失上就是因为用了通用日志框架却没按审计标准建模。2.2 三层日志分治访问层、业务层、审计层各司其职不越界FastapiAdmin 的日志不是一股脑全塞进一个文件。它强制划分为三个物理隔离、格式独立、存储策略不同的日志流访问日志access.log纯 HTTP 层类 Nginx 格式。只记录remote_addr - [datetime] method path protocol status bytes referer user_agent。目的很明确给运维做流量分析、WAF 做攻击识别、CDN 做缓存命中率统计。它绝不记录任何业务字段避免敏感信息泄露和日志膨胀。业务日志app.logFastapiAdmin 自定义的结构化日志。每条都是 JSON固定字段包括timestamp,level,module,function,line,trace_id,event_type,actor,target,context,duration_ms。这是开发和产品最常看的日志用于功能调试、用户行为分析、性能瓶颈定位。关键点在于context字段是动态的导出操作填{file_size_bytes: 12987654, rows_exported: 3247}删除操作填{deleted_ids: [101,102,103], cascade: true}。审计日志audit.log最严格的一层。格式为 CSV便于导入审计系统字段固定为timestamp,actor_id,actor_role,ip_address,event_type,target_type,target_id,action_result,details_hash。details_hash是context字段的 SHA256 值确保日志不可篡改。此日志必须写入独立磁盘分区且禁止任何应用进程直接读取只允许审计系统通过专用 API 拉取这是等保三级的硬性要求。这三层不是靠代码里 if-else 分流而是通过 Python 的logging.Filter和logging.Handler组合实现。我见过有团队试图用 loguru 的add()多次注册 handler结果导致同一条日志被重复处理、trace_id 错乱。正确做法是一个Logger实例挂载三个Filter分别匹配event_type前缀每个 Filter 对应一个RotatingFileHandlerhandler 的filename和formatter各不相同。这样既保证日志源头唯一又实现物理隔离。2.3 核心配置参数的底层作用机制它们不是开关而是日志 DNA 的编码器FastapiAdmin 的settings.py里那些看似普通的配置项实际是日志行为的基因序列。改一个参数整个日志生态就变LOG_LEVEL表面是控制输出级别实质是日志采样率调节阀。设为INFO时所有AdminEvent都记录设为WARNING时只有event_type包含ERROR或DENIED的才记录设为CRITICAL时仅记录系统级崩溃如数据库连接池耗尽。这不是为了省磁盘而是降低日志噪音。我们曾因LOG_LEVELDEBUG导致 audit.log 每天 20GBELK 集群直接 OOM。LOG_FORMAT决定日志是否“可机器阅读”。默认值json强制所有 handler 输出 JSON若设为text则只对 access.log 生效因其格式固定app.log 和 audit.log 仍保持结构化。这里有个陷阱LOG_FORMATjson时logging.Formatter的format参数会被忽略实际由jsonlogger.JsonFormatter控制字段顺序和类型转换。很多团队误以为改format就能加字段结果发现新字段根本不出现。LOG_FILE_SIZE不是简单的“文件多大就切”而是影响日志检索效率的关键阈值。设为1048576010MB时单个日志文件约含 20 万条记录Elasticsearch 的terms聚合查询响应在 200ms 内设为104857600100MB时同样查询要 1.8s。因为 ES 的 segment 合并策略对小文件更友好。我们线上最终定为1572864015MB是经过 3 周压测得出的平衡点。LOG_RETENTION_DAYS表面是清理策略实则是法律合规的刻度尺。GDPR 要求用户操作日志保留不超过 6 个月金融行业要求交易日志保留 5 年。FastapiAdmin 的清理不是简单rm -f而是先将过期日志压缩为.tar.gz上传至冷备对象存储如 AWS S3 Glacier再执行os.remove()。LOG_RETENTION_DAYS180时清理脚本每天凌晨 2 点执行但会跳过audit.log.*.gz文件——因为审计日志需永久保留只是移出热存储。这些参数共同构成 FastapiAdmin 日志的“数字指纹”。当你看到一份日志样本就能反推出它的LOG_LEVEL看 INFO/WARNING 比例、LOG_FORMAT看是 JSON 还是文本、LOG_FILE_SIZE看文件大小分布、LOG_RETENTION_DAYS看文件名时间戳跨度。它们不是孤立的配置而是一个协同工作的有机体。3. 核心配置参数详解每个参数背后的血泪教训与实操公式3.1 LOG_LEVEL从“全量记录”到“精准捕获”的临界点选择LOG_LEVEL的取值不是DEBUG/INFO/WARNING/ERROR/CRITICAL的简单枚举而是 FastapiAdmin 内部AdminEvent类的severity_map映射表。这个映射决定了哪些事件类型会被记录# fastapi_admin/loggers/event_logger.py severity_map { LOGIN_SUCCESS: INFO, LOGIN_FAILED: WARNING, EXPORT_START: INFO, EXPORT_SUCCESS: INFO, EXPORT_FAILED: ERROR, DELETE_START: WARNING, # 删除是高危操作即使成功也记 WARNING DELETE_SUCCESS: WARNING, PERMISSION_DENIED: WARNING, DATABASE_ERROR: ERROR, SYSTEM_CRASH: CRITICAL, }关键洞察LOG_LEVELINFO时DELETE_SUCCESS事件也会被记录因为它映射到WARNING而WARNING INFO但LOG_LEVELWARNING时EXPORT_SUCCESS映射INFO就被过滤掉了。所以LOG_LEVEL实际是事件严重性阈值而非日志级别本身。实操建议开发环境LOG_LEVELDEBUG。此时会额外记录 SQL 查询语句LOG_INCLUDE_SQLTrue时、HTTP 请求 body仅限非敏感接口、函数入参快照。但注意DEBUG模式下audit.log会被禁用因为审计日志不允许调试信息。测试环境LOG_LEVELINFO。覆盖所有正常业务流但过滤掉调试细节。重点观察EXPORT_SUCCESS和DELETE_SUCCESS是否按预期记录。生产环境LOG_LEVELWARNING。这是我们的黄金标准。它保留所有异常EXPORT_FAILED,PERMISSION_DENIED、所有高危操作DELETE_*、所有权限相关事件同时过滤掉海量的EXPORT_SUCCESS每天数万条。磁盘节省 67%ELK 查询速度提升 3.2 倍。计算公式有效日志量 ≈ Σ(事件频率 × severity_map[事件] ≥ LOG_LEVEL)例如某系统每天EXPORT_SUCCESS20,000 次INFODELETE_SUCCESS120 次WARNINGPERMISSION_DENIED85 次WARNING。LOG_LEVELINFO→ 20,000 120 85 20,205 条/天LOG_LEVELWARNING→ 0 120 85 205 条/天节省率 (20205 - 205) / 20205 ≈ 99%提示不要在生产环境设LOG_LEVELDEBUG。我们曾因一次临时调试开启 DEBUG3 小时内 audit.log 写满 500GB 磁盘导致数据库连接池因磁盘 I/O 阻塞而超时整个 admin 后台雪崩。恢复花了 4 小时。3.2 LOG_FORMATJSON 结构化日志的字段契约与兼容性陷阱LOG_FORMATjson时FastapiAdmin 使用python-json-logger库但不是原生版本而是打了补丁的 fork。补丁内容包括强制添加trace_id字段即使未启用 OpenTelemetry、将context字典扁平化为context_*前缀的键如context_file_size_bytes: 12987654、对actor和target对象进行安全序列化自动脱敏password,token等字段。默认 JSON Schema 如下精简版{ timestamp: 2024-06-15T08:23:45.123Z, level: INFO, module: fastapi_admin.loggers.event_logger, function: log_event, line: 42, trace_id: 0af7651916cd43dd8448eb211c80319c, event_type: EXPORT_SUCCESS, actor: {id: 1024, role: super_admin, ip: 192.168.1.100}, target: {type: UserModel, id: null}, context: {file_size_bytes: 12987654, rows_exported: 3247}, duration_ms: 8234.56, details_hash: sha256:... }关键字段说明trace_id由opentelemetry.trace.get_current_span().get_span_context().trace_id生成。若未集成 OpenTelemetry则 fallback 到uuid.uuid4().hex[:32]。这是跨服务追踪的唯一标识必须存在。actor.ip不是request.client.host而是X-Forwarded-For头的首 IP经 Nginx 反向代理后。我们专门写了get_client_ip()函数处理多层代理。context是动态字典但字段名必须符合snake_case且不能含空格或特殊字符。否则 JSON 序列化失败整条日志丢失。兼容性陷阱ELK/Kibana 字段映射context.file_size_bytes在 Kibana 中会被映射为context.file_size_bytes.long但若日志中偶尔出现context.file_size_bytes: 12MB字符串会导致 mapping conflict。解决方案在context字典赋值前强制类型转换int(context.get(file_size_bytes, 0))。Logstash 过滤Logstash 的jsonfilter 默认将timestamp解析为timestamp但 FastapiAdmin 的timestamp是 ISO8601 字符串。需在 Logstash 配置中加date { match [timestamp, ISO8601] }否则时间线错乱。注意LOG_FORMATtext仅对access.log生效且格式固定为%(asctime)s %(levelname)s %(message)s。app.log和audit.log永远是 JSON 或 CSV不受此参数影响。这是设计使然不是 bug。3.3 LOG_FILE_SIZE 与 LOG_RETENTION_DAYS磁盘空间与合规性的动态平衡术这两个参数必须联合调优单独设置毫无意义。公式如下每日日志体积 ≈ (日均事件数 × 单事件平均 JSON 字节数) / (LOG_FILE_SIZE / 1024 / 1024)总磁盘占用 ≈ (每日日志体积 × LOG_RETENTION_DAYS) × 1.31.3 是压缩和元数据冗余系数单事件平均 JSON 字节数实测值EXPORT_SUCCESS约 420 字节含长contextPERMISSION_DENIED约 280 字节context极简LOGIN_SUCCESS约 190 字节加权平均按我们系统比例EXPORT 60%, DELETE 15%, LOGIN 25%≈ 342 字节代入计算日均事件 20,000 条 → 每日原始日志体积 20,000 × 342 6,840,000 字节 ≈ 6.5MB设LOG_FILE_SIZE1572864015MB→ 每日产生约 1 个 app.log 文件设LOG_RETENTION_DAYS90→ 理论占用 6.5MB × 90 × 1.3 ≈ 760MB但这是理想值。真实世界有峰值促销期间 EXPORT 事件暴增 5 倍单日达 100,000 条体积 32.5MB需 3 个文件。因此LOG_FILE_SIZE必须按P95 峰值流量设计而非日均。我们的实操方案磁盘分区规划为日志单独划分/var/log/fastapi-admin分区大小 (P95 日志体积 × LOG_RETENTION_DAYS × 1.5)。例如 P95 体积 45MBLOG_RETENTION_DAYS90→ 分区大小 45 × 90 × 1.5 6,075MB ≈ 6GB。轮转策略使用logging.handlers.RotatingFileHandlerbackupCount30。这意味着最多保留 30 个历史文件约 30 天超出后自动删除最老的。LOG_RETENTION_DAYS控制的是归档后冷备的天数不是热文件数量。冷备自动化每日凌晨 1 点执行脚本将app.log.*和audit.log.*压缩为app-20240615.tar.gz上传至 S3然后find /var/log/fastapi-admin -name app.log.* -mtime 30 -delete。LOG_RETENTION_DAYS90即在此脚本中体现。提示LOG_RETENTION_DAYS设为 0 表示永不清除但磁盘会满。设为负数如 -1则禁用自动清理必须手动管理。我们线上从不设 0 或负数最小值为 30一个月这是运维 SLA 的底线。3.4 LOG_TRACE_ID_HEADER分布式追踪的生命线也是安全防线LOG_TRACE_ID_HEADERX-Request-ID是 FastapiAdmin 的默认值但它必须与你的 API 网关如 Kong、Traefik或负载均衡器如 Nginx的配置完全一致。否则trace_id字段就是一堆随机字符串失去追踪价值。工作原理用户请求到达 NginxNginx 生成X-Request-ID: 0af7651916cd43dd8448eb211c80319c并透传FastapiAdmin 的TraceIdMiddleware从中提取存入request.state.trace_id所有AdminEvent日志自动注入此trace_id当该请求调用下游服务如用户服务FastapiAdmin 会将X-Request-ID作为X-B3-TraceId透传OpenTracing 标准关键配置点Nginx 配置location /admin/ { proxy_set_header X-Request-ID $request_id; # $request_id 是 Nginx 内置变量 proxy_pass http://fastapi-admin; }FastapiAdmin settings.pyLOG_TRACE_ID_HEADER X-Request-ID# 必须与 Nginx 的 header 名完全一致LOG_TRACE_ID_PROPAGATE True# 启用向下游透传安全考量X-Request-ID是公开 header任何人都能伪造。但 FastapiAdmin 的TraceIdMiddleware有校验逻辑只接受长度为 32 的十六进制字符串即 UUID v4 的 hex 形式。若收到X-Request-ID: hacker123中间件会忽略并生成新的 trace_id。这防止了 trace_id 注入攻击。注意LOG_TRACE_ID_HEADER不能设为X-Forwarded-For或User-Agent。我们曾因错误配置导致所有日志trace_id都是客户端 IP结果在 ELK 中看到“同一 trace_id 下有 1000 个不同用户”彻底废掉追踪功能。修复后用 Kibana 的Discover功能输入trace_id: 0af76519...瞬间定位到该请求的全部日志、SQL、下游调用排查时间从 2 小时缩短到 47 秒。3.5 LOG_INCLUDE_SQL 与 LOG_SANITIZE_FIELDSDB 操作日志的双刃剑LOG_INCLUDE_SQLTrue时FastapiAdmin 会在app.log中记录每条 SQLAlchemy 查询的完整 SQL 语句、参数、执行时间。这极其有用但也极其危险。实测效果开启后EXPORT_SUCCESS事件日志体积增加 300%因context中多了sql_query和sql_params字段sql_query是格式化后的字符串如SELECT * FROM users WHERE status ? AND created_at ?sql_params是参数列表如[1, 2024-01-01]但风险在于若sql_params包含明文密码如INSERT INTO users (password) VALUES (?)日志就泄露了 PII若sql_query含有用户输入如WHERE name LIKE %{user_input}%日志就成了 SQL 注入证据解决方案是LOG_SANITIZE_FIELDSLOG_SANITIZE_FIELDS [ password, passwd, token, auth_token, api_key, secret, private_key, certificate ]FastapiAdmin 的日志处理器会扫描sql_params和context字典对所有 key 匹配LOG_SANITIZE_FIELDS的字段将其值替换为***SANITIZED***。例如sql_params [admin, mysecretpassword123]→ 记录为[admin, ***SANITIZED***]context {user: {name: Alice, password: 123456}}→ 记录为{user: {name: Alice, password: ***SANITIZED***}}实操心得LOG_INCLUDE_SQLTrue仅在性能调优期开启上线后立即设为False。我们用它抓出 3 个 N1 查询问题优化后 QPS 提升 40%。LOG_SANITIZE_FIELDS必须定期更新。当新增一个UserModel字段ssn社会安全号必须立刻加入列表否则审计通不过。永远不要信任 ORM 的__repr__()方法来生成日志。我们曾用str(user)记录用户对象结果user.password_hash被完整打印出来。正确做法是user.dict(exclude{password_hash})。提示LOG_INCLUDE_SQL和LOG_SANITIZE_FIELDS是一对共生参数。单独开启LOG_INCLUDE_SQL而不配LOG_SANITIZE_FIELDS等于在日志里埋雷。我们线上环境LOG_INCLUDE_SQLFalse仅在每周二上午 10 点开启 2 小时配合 APM 工具做专项分析。4. 实操全流程从零配置到生产就绪的 7 步落地清单4.1 第一步初始化日志目录与权限被忽略的致命起点很多团队跳过这步直接跑uvicorn结果日志写入失败还以为是代码问题。正确流程# 创建专用日志目录必须 sudo mkdir -p /var/log/fastapi-admin/{app,access,audit} # 设置属主和权限关键 sudo chown -R www-data:www-data /var/log/fastapi-admin sudo chmod 755 /var/log/fastapi-admin sudo chmod 644 /var/log/fastapi-admin/*.log # 初始化空文件为什么必须chown给www-data因为 Uvicorn 进程默认以www-data用户运行Ubuntu/Debian若目录属主是root进程无权写入日志静默失败。我们曾因此线上三天无任何日志直到用户投诉“操作没反应”才发现app.log是空文件。注意/var/log/fastapi-admin目录不能设chmod 777。这是安全红线。644对文件足够755对目录足够。4.2 第二步settings.py 核心参数配置抄作业版# fastapi_admin/settings.py import os from pathlib import Path # 日志基础路径 LOG_DIR Path(/var/log/fastapi-admin) # 1. 日志级别生产环境用 WARNING LOG_LEVEL WARNING # 2. 日志格式全部 JSON LOG_FORMAT json # 3. 文件大小15MB平衡检索与轮转 LOG_FILE_SIZE 15728640 # 15 * 1024 * 1024 # 4. 保留天数90天满足多数合规要求 LOG_RETENTION_DAYS 90 # 5. Trace ID Header与 Nginx 保持一致 LOG_TRACE_ID_HEADER X-Request-ID LOG_TRACE_ID_PROPAGATE True # 6. SQL 日志生产关闭仅调试开启 LOG_INCLUDE_SQL False # 7. 敏感字段脱敏PII 字段全覆盖 LOG_SANITIZE_FIELDS [ password, passwd, token, auth_token, api_key, secret, private_key, certificate, ssn, id_card, phone, email ] # 8. 审计日志专用配置必须 AUDIT_LOG_PATH LOG_DIR / audit.log AUDIT_LOG_ROTATION 10 MB # audit.log 单独轮转 AUDIT_LOG_RETENTION 3650 # 审计日志保留 10 年这份配置是我们三个项目验证过的最小可行集。LOG_SANITIZE_FIELDS中的email是新加的因为 GDPR 要求邮箱也属 PII。AUDIT_LOG_RETENTION3650是金融客户的硬性要求。4.3 第三步Nginx 反向代理配置让 trace_id 流通起来# /etc/nginx/sites-available/fastapi-admin upstream fastapi-admin { server 127.0.0.1:8000; } server { listen 443 ssl; server_name admin.yourcompany.com; # 关键生成并透传 X-Request-ID proxy_set_header X-Request-ID $request_id; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host; location /admin/ { proxy_pass http://fastapi-admin/; # 传递所有 headers特别是 X-Request-ID proxy_pass_request_headers on; } # 访问日志单独配置不走 FastapiAdmin 的 access.log access_log /var/log/nginx/fastapi-admin-access.log; error_log /var/log/nginx/fastapi-admin-error.log; }$request_id是 Nginx 的内置变量自动生成 UUID v4。proxy_pass_request_headers on确保X-Request-ID不被丢弃。这步做完app.log里的trace_id才是真实的请求 ID。4.4 第四步Logstash 配置让 JSON 日志可搜索# /etc/logstash/conf.d/fastapi-admin.conf input { file { path /var/log/fastapi-admin/app.log* start_position end sincedb_path /dev/null # 避免重启后重复读取 codec json } } filter { # 解析 timestamp 为 timestamp date { match [timestamp, ISO8601] target timestamp } # 将 context.* 提升为顶级字段便于 Kibana 聚合 mutate { rename { context [context] } } # 如果 context 是嵌套对象展开它需根据实际 JSON 结构调整 # json { # source context # target context # } } output { elasticsearch { hosts [http://es-cluster:9200] index fastapi-admin-app-%{YYYY.MM.dd} } }关键点sincedb_path /dev/null防止 Logstash 重启后重读旧日志。index fastapi-admin-app-%{YYYY.MM.dd}实现按天索引这是高效查询的基础。4.5 第五步审计日志冷备脚本合规落地的最后一步#!/bin/bash # /opt/scripts/rotate-audit-log.sh LOG_DIR/var/log/fastapi-admin DATE$(date %Y%m%d) ARCHIVE_DIR/mnt/backup/fastapi-admin/audit # 创建归档目录 mkdir -p $ARCHIVE_DIR # 压缩当天的 audit.log注意audit.log 不轮转每天一个新文件 if [ -f $LOG_DIR/audit.log ]; then mv $LOG_DIR/audit.log $LOG_DIR/audit.log.$DATE gzip $LOG_DIR/audit.log.$DATE # 上传到 S3需 awscli 配置好 aws s3 cp $LOG_DIR/audit.log.$DATE.gz s3://your-bucket/audit/$DATE/ # 清理本地保留 30 天热文件 find $LOG_DIR -name audit.log.*.gz -mtime 30 -delete fi此脚本每日执行确保audit.log永久可追溯。aws s3 cp命令需提前配置 IAM Role禁止使用 Access Key。4.6 第六步验证日志链路5 分钟快速巡检启动服务后执行以下命令验证# 1. 检查日志文件是否存在且可写 ls -la /var/log/fastapi-admin/ # 应看到 app.log, access.log, audit.log且属主为 www-data # 2. 触发一个 admin 操作如登录 curl -X POST https://admin.yourcompany.com/api/login \ -H Content-Type: application/json \ -d {username:admin,password:pass} # 3. 实时查看 app.log tail -f /var/log/fastapi-admin/app.log | jq . | head -n 5 # 应看到 JSON含 trace_id, event_type, actor, context # 4. 检查 trace_id 是否一致 # 在 Nginx access log 中找请求 grep POST /api/login /var/log/nginx/fastapi-admin-access.log | tail -1 # 提取 X-Request-ID再在 app.log 中 grep应匹配若jq不可用用python -m json.tool替代。这步必须做否则后续所有日志分析都是空中楼阁。4.7 第七步Kibana 看板配置让日志产生业务价值创建三个核心看板审计看板字段event_type,actor.role,target.type,action_result。可视化饼图事件类型分布、表格最近 100 条 PERMISSION_DENIED、地理地图actor.ip解析地理位置。性能看板字段duration_ms,event_type,trace_id。可视化直方图duration_ms分布、折线图每分钟平均duration_ms、TopN最慢的 10 个event_type。安全看板字段event_type, actor