在传统的单体应用中,日志管理相对简单。我经历过一个电商项目从单体架构迁移到微服务的痛苦过程——当系统被拆分成20多个服务后,每个服务都有自己的日志文件。某次大促期间出现支付异常,我们不得不在10台服务器上翻查不同的日志文件,光是定位问题就花了4个小时。
这就是微服务架构下的典型痛点:
SEQ作为专门为现代应用设计的日志系统,提供了三大核心能力:
实测一个包含15个微服务的系统接入SEQ后,故障定位时间从平均47分钟缩短到8分钟。特别是在处理异步消息场景时,通过@MessageId查询能快速还原完整的业务流水线。
推荐使用Docker Compose部署,这个配置模板经过我们3个生产环境验证:
yaml复制version: '3'
services:
seq:
image: datalust/seq:latest
environment:
- ACCEPT_EULA=Y
- SEQ_CACHE_SYSTEMRAMTARGET=0 # 小内存环境禁用缓存
volumes:
- ./data:/data
ports:
- 8001:80
- 5341:5341
deploy:
resources:
limits:
memory: 4G
关键参数说明:
volumes映射持久化目录,防止容器重启丢失数据5341端口用于接收日志数据,8001是Web界面启动后访问http://服务器IP:8001,你会看到极简的登录界面。首次使用需要设置管理员密码,建议通过环境变量预置:
bash复制export SEQ_PASSWORD_HASH=$(docker run --rm datalust/seq config hash | tail -n 1)
docker compose up -d
对于生产环境,我们采用"双节点+共享存储"的部署架构:
code复制[Service A] [Service B] [Service C]
| | |
v v v
[ SEQ节点1 ] ←→ [ NFS存储 ] ←→ [ SEQ节点2 ]
↑ ↑ ↑
| | |
[ 负载均衡 ] [ 定期备份 ] [ 冷备节点 ]
具体实施要点:
/data目录共享crontab每天凌晨执行日志压缩归档SEQ_METASTORE_POSTGRES_CONNECTIONSTRING将元数据存入PostgreSQL这是经过优化的nlog.config配置片段:
xml复制<target name="seq" xsi:type="Seq" serverUrl="http://seq:5341">
<property name="Application" value="${appsetting:name=App.Name}" />
<property name="Environment" value="${environment:variable=ASPNETCORE_ENVIRONMENT}" />
<property name="TraceId" value="${aspnet-TraceIdentifier}" />
<property name="UserId" value="${aspnet-User-IdentityName}" />
</target>
关键改进点:
${appsetting}引用appsettings.json配置在Controller中这样记录结构化日志:
csharp复制_logger.LogInformation("订单创建成功 {@Order}", new {
OrderId = order.Id,
TotalAmount = order.Amount,
Items = order.Items.Select(i => new {i.SkuId, i.Quantity})
});
SEQ会自动将@Order对象展开为可查询字段,比如可以通过Items[0].SkuId = 'ABC123'精确查询。
在高并发场景下,我总结出这些经验:
xml复制<target xsi:type="BufferingWrapper"
bufferSize="500"
flushTimeout="5000">
<target xsi:type="Seq" ... />
</target>
csharp复制loggerFactory.AddSeq(new SeqLoggerConfiguration {
SampleRate = level => level >= LogLevel.Warning ? 1.0f : 0.1f
});
<when>条件过滤敏感字段在订单处理流程中,我们需要追踪从购物车→支付→物流的完整链路。解决方案是:
X-Correlation-Idcsharp复制// 网关Middleware
using(MappedDiagnosticsLogicalContext.SetScoped("CorrelationId", context.Request.Headers["X-Correlation-Id"]))
{
await _next(context);
}
CorrelationId = '值'查询完整链路根据多年运维经验,建议采用这样的分级标准:
| 级别 | 场景示例 | 存储策略 |
|---|---|---|
| Verbose | 调试信息、方法入参 | 仅开发环境保留 |
| Debug | 业务流程关键节点 | 保留7天 |
| Info | 业务操作记录 | 保留30天 |
| Warning | 异常重试、降级操作 | 保留90天 |
| Error | 系统异常、第三方调用失败 | 永久保留 |
在SEQ中创建对应的保留策略:
sql复制@Level = 'Debug' | retain for 7d
@Level = 'Info' | retain for 30d
在SEQ仪表板创建这样的预警规则:
sql复制from stream
where @Level = 'Error'
group by Application, MessageTemplate
having count() > 5 within 1h
配置邮件通知模板:
code复制[紧急] {Application}出现异常: {MessageTemplate}
发生次数: {count}
最近实例: {format_timestamp(max(@Timestamp))}
找出最耗时的API请求:
sql复制select
ApiPath,
avg(ElapsedMs) as AvgTime,
count() as RequestCount
from stream
where startsWith(MessageTemplate, 'API执行耗时')
group by ApiPath
order by AvgTime desc
limit 10
配合Grafana可以生成这样的监控看板:
code复制[请求成功率] [平均响应时间] [TOP10慢接口]
[错误类型分布] [服务依赖拓扑] [资源水位]
最近在处理一个内存泄漏问题时,通过SEQ的gc_heap_size指标关联分析,最终定位到是Redis连接池未释放导致的。这种多维度的日志分析能力,是传统ELK方案难以实现的。