.NET ILogger日志体系详解:从结构化日志到生产级配置实战
做后端服务这些年日志一直是我觉得最值得花心思打磨的基础设施。很多兄弟可能觉得日志嘛不就是到处打Console.WriteLine或者Debug.WriteLine出了问题打开控制台看一下就行。但等你真正把一个服务跑上生产几千个请求涌进来的时候这种打日志的方式基本等于没有日志——信息全混在一起没有级别、没有上下文排错的时候只能靠肉眼扫。.NET生态里ILogger这套抽象就是为了解决这个问题而生的它给整个日志系统提供了一套统一的接口让Console、文件、数据库、第三方日志平台都可以通过同一套代码接入。这篇内容我就基于自己这几年在.NET项目里折腾ILogger的实操经验从基础概念到生产可用的日志系统搭建全捋一遍。不管你是刚入门.NET不久的新手还是已经写了几年服务端代码想优化日志方案的老手里面提到的东西应该都能用得上。我会把原理、代码、踩坑三部分混在一起讲尽量做到看完就能照着改。1. 日志问题为什么值得花大力气解决我先聊一个比较扎心的场景。有一次线上服务半夜报警某个接口的失败率突然飙升我打开服务器一看进程还活着数据库连接池正常内存也没爆。当时日志是直接写在文件里的但每个线程都在用自己的方式打日志有的打在Console有的打在单独的txt文件里内容完全没有统一格式。我花了整整两个多小时靠grep和肉眼比对才勉强定位到一个Redis连接超时的问题。那次之后我下决心把所有日志入口统一起来ILogger就是我最终选择的方向。1.1 没有结构化日志的苦日子现在回头看当时最大的痛点其实不是日志打得太少而是日志打得“太乱”。如果你打过类似这种日志2024-03-15 10:23:45 - User login failed看着好像有时间和消息但真正排查问题的时候你会发现你根本不知道是哪个用户、哪个接口、哪台机器、哪个请求ID。所有日志就像流水账一样堆在一起一旦业务量上来查一条日志跟大海捞针没区别。结构化日志是解决这个问题的关键思路。所谓结构化就是不要只写一串字符串而是把关键信息拆成一个个字段比如用户ID、订单号、请求路径、耗时、错误码存成JSON或者其他格式。ILogger天然支持这种习惯你可以写logger.LogWarning(用户 {UserId} 下单失败订单号 {OrderId}原因 {Reason}, userId, orderId, reason)实际输出的时候会变成一组清晰的键值对。这套机制配合任何日志平台都能用远比你自己拼字符串要可靠得多。提示不要用字符串拼接去拼日志比如$用户{userId}下单失败。一旦某个参数值为null或者格式转义出错影响的可能是一整条关键日志而且拼接出来的内容在日志检索系统里完全没法按字段过滤。永远把参数放在消息模板后面。1.2 ILogger在整个日志体系中的位置理解ILogger之前先要看清.NET日志体系的三层结构。最顶层是ILoggerT这是你在业务代码里直接用的对象中间一层是ILoggerFactory负责创建Logger最底层是ILoggerProvider真正决定日志写到哪儿去——控制台、文件、Seq、ElasticSearch都靠Provider实现。这三层分工非常明确业务代码只跟ILoggerT打交道完全不需要知道日志最终去了哪里。你写代码的时候调的是logger.LogInformation(...)但等你把Provider从Console换成Seq业务代码一行都不用改。这就是面向抽象编程的价值也是ILogger设计最漂亮的地方之一。我记得有个朋友之前吐槽过项目里日志代码到处是Trace.WriteLine、Console.WriteLine、自己封装的一个静态类换一个日志方案就得满项目改。用了ILogger抽象之后这些东西全部被收编到统一的管道里后续换任何日志后端都只是改配置的事。这一点对于长期维护的项目价值极大。2. ILogger核心架构拆解工厂、Provider与Logger这一节进入核心原理。你自己可以画一张关系图ILoggerFactory是总装车间ILoggerProvider是生产线上不同的包装工位ILogger是最终交付到你手里的产品。你在代码里拿到一个ILoggerT背后其实是工厂根据T这个类型创建出来的、带着类型上下文的Logger实例。2.1 三层抽象各自干什么逐个说。ILoggerFactory是整个日志系统的入口它负责维护一批Provider实例并提供创建ILogger的方法。你可以在依赖注入容器里注册任意多个Provider工厂会把它们组合起来意味着你写一条日志可以同时写到Console、写到文件、推到远端日志平台。ILoggerProvider是最底层的写作者它定义了日志怎么格式化、写到什么目标。最常见的ConsoleLoggerProvider、EventLogProvider、第三方的Serilog的Provider都是这个接口的实现。ILoggerT和前两者不太一样它在工厂之上多了一个泛型参数T。这个T通常是你当前的类比如OrderService。这样做的核心价值在于日志输出时可以自动带上类别Category信息也就是这条日志来自哪个类。在日志检索系统里按类别过滤是再常见不过的操作ILoggerOrderService打出来的日志在文件或者日志平台里会记录CategoryOrderService排查起来非常直观。需要特别注意的是这三个接口的生命周期是不同的。ILoggerFactory通常是单例Provider也建议保持单例而ILoggerT本身是轻量级对象你每次通过构造函数注入拿到的实例都值得放心使用。正因为Logger是轻量的所以不要在业务方法里用ILoggerFactory.CreateLogger手动创建Logger——直接构造函数注入ILoggerT是最标准、最不容易出错的方式。2.2 依赖注入注册的正确姿势在ASP.NET Core项目里日志系统的默认集成已经做得相当好。你只需要在Program.cs里调用builder.Logging相关方法就能完成注册。最简单的一段配置长这样var builder WebApplication.CreateBuilder(args); builder.Logging.ClearProviders(); builder.Logging.AddConsole(); builder.Logging.AddDebug(); builder.Logging.AddEventLog(); var app builder.Build();ClearProviders()这一行值得单独说一下。ASP.NET Core默认自带Console、Debug、EventSource等Provider但很多时候你只想保留自己关心的那几个这时候先清空再逐个添加能避免很多莫名其妙的多份输出。比如你在Windows服务里跑的时候默认的Console输出压根看不到反而白白消耗IO清掉重加是更干净的做法。注册完成后在任意一个类里构造函数注入ILoggerT就能用了。这里有个很多新手容易忽略的点你注入的泛型参数T一定要写当前类而不是写不带泛型的ILogger。虽然框架也支持非泛型的ILogger但非泛型版本打出来的日志不带类别信息在检索和过滤上会吃亏。养成写ILoggerT的习惯算是最低成本提升日志体验的动作之一。2.3 为什么宁可注入ILogger 而不是ILogger我见过有些团队为了方便直接在项目里封装了一个静态日志类里面存了一个全局的ILogger所有业务代码都往那儿打。这种做法在功能上能跑但日志的类别信息就全丢了——你没办法从日志系统里一眼看出这条日志是哪个服务、哪个类打出来的。而ILoggerT把T作为类别的一部分天然解决了这个问题。另外ILoggerT还能配合过滤器做更细粒度的控制。比如某个第三方库Microsoft.EntityFrameworkCore的SQL日志太吵你就可以在配置里只针对它的类别调整级别而不会影响全局配置。如果你用的是全局静态Logger这种精细控制基本做不到只能把整个系统的日志级别调低最后被海量日志淹没。从依赖注入的角度看ILoggerT的实现已经和容器深度集成每一个泛型实参都会生成一个独立的Logger实例背后复用的是同一个工厂和Provider池。所以不要担心注入ILoggerOrderService和ILoggerPaymentService会产生性能问题它们共享的底层资源是一致的代价几乎可以忽略不计。3. 上手操作五分钟搭出一套可用的日志系统原理讲多了容易飘咱们直接上手。如果你现在手头有一个新的ASP.NET Core项目按照下面的步骤五分钟就能得到一套具备基本生产素养的日志输出。3.1 基础配置与Provider选择我先说Provider怎么选。日常开发阶段AddConsole()是最直观的信息直接打到控制台配合开发环境跑起来很方便。生产阶段如果你用的是Linux服务器最常见的做法是把日志写到标准输出然后由systemd、Docker、K8s这类宿主环境统一采集如果用的是Windows服务AddEventLog()写Windows事件日志也可以作为兜底方案。更复杂一点你可能会接Serilog再推到ElasticSearch或Seq那是另一个话题核心思路不变多个Provider可以同时存在互不干扰。配置代码上面已经给过了。我再给一个稍微完整一点的版本加入了日志级别控制builder.Logging.ClearProviders(); builder.Logging.AddConsole(options { options.FormatterName json; }); builder.Logging.AddFilter(Microsoft.EntityFrameworkCore, LogLevel.Warning); builder.Logging.AddFilter(System, LogLevel.Warning); builder.Logging.SetMinimumLevel(LogLevel.Information);这段配置的核心思路是全局最低级别设为Information把框架自带的噪音压到Warning业务代码正常输出Info。很多项目直接不配Filter结果Entity Framework的SQL调试日志全打出来磁盘一天写几个GB这是最常见的日志失控事故之一。3.2 日志级别如何影响实际写入日志级别这件事表面上谁都懂但实际用起来很多人把握不好。.NET定义了六个级别从低到高分别是Trace、Debug、Information、Warning、Error、Critical。我自己的经验是Trace和Debug主要用于本地开发调试不要在生产开着Information记录业务关键节点比如下单成功、支付回调、订单状态变更Warning表示有问题但服务还能继续跑比如重试了三次才成功Error和Critical则必须保证完整上下文包括异常堆栈、请求ID、关键参数。级别设置有一个原则生产环境的日志级别要能保证你抓到足够多的信息但同时要控制总量。我见过一个团队为了“怕漏信息”把生产环境开到Trace结果一天日志几十GB真正的问题被淹没在噪声里检索一次要半天。后来他们老老实实调回Information配合结构化字段发现问题反而更快了。日志不是越多越好而是越精准越好。下面这个表格可以帮你快速判断该怎么选级别级别使用场景生产建议Trace框架内部跟踪、变量级调试默认关闭Debug开发期调试、临时输出按需开启Information业务关键节点、正常流程记录默认开启Warning异常但不致命、需要关注的重试默认开启Error当前操作失败影响业务默认开启Critical进程级故障、必须立即处理默认开启注意SetMinimumLevel设置的是全局下限AddFilter可以做更细的覆盖。两者的关系是“取更严格的那个”。如果你的全局是Information但某个类需要Debug必须用Filter单独放宽反过来如果只想关掉某个库的日志用Filter收紧即可。3.3 结构化日志字段与模板设计这里重点说说消息模板。ILogger的接口签名是void Log(LogLevel level, string message, params object[] args)但真正好用的是泛型扩展方法。你可以写logger.LogInformation(用户 {UserId} 创建订单 {OrderId} 成功金额 {Amount} 元, userId, orderId, amount);注意这里的{UserId}不是占位符拼接而是结构化字段名。输出的日志会变成类似User 12345 create order 20240315001 success, amount 99.00但在支持结构化日志的系统里UserId、OrderId、Amount会被解析成独立字段。这意味着你可以像查数据库一样查询日志where UserId 12345而不是靠人在文本里搜。设计消息模板时我有几个自己的规矩供你参考每个日志消息尽量包含请求链路ID比如TraceId或RequestId方便串起一次请求的全部日志。业务日志里带上业务主键比如订单号、用户ID而不是只写“下单失败”。异常日志必须包含完整异常对象用logger.LogError(ex, 处理订单 {OrderId} 时发生异常, orderId)不要只传ex.Message否则堆栈就丢了。模板字符串里的字段名保持稳定不要今天叫userID明天叫user_id否则日志查询体验会非常糟糕。4. 进阶实战Filter、Scope与自定义Provider基础配置跑通之后你大概率会遇到两个问题日志太吵以及日志之间缺少关联。本节就是来解决这两件事的。4.1 用Filter精确控制每个命名空间的日志噪声ASP.NET Core里日志过滤器通常写在配置文件里也可以代码配置。我推荐用代码配置理由很简单配置文件的格式容易写错而且编译期发现不了。代码配置的好处是强类型、可重构、支持条件判断。举个例子。你在用Entity Framework Core它的SQL日志在Debug级别下非常详细但生产环境你其实只关心慢查询和错误。可以这样配builder.Logging.AddFilter(Microsoft.EntityFrameworkCore.Database.Command, LogLevel.Warning);这条配置表示只保留Microsoft.EntityFrameworkCore.Database.Command类别下的Warning及以上日志其余全部忽略。注意Filter的匹配是前缀匹配你写了Microsoft.EntityFrameworkCore那么它下面的所有子类别都会受这个规则影响。如果你要精细控制就要写足够长的类别前缀。多个Filter之间是有优先级顺序的规则是“最长的匹配前缀生效”。比如你同时配了Microsoft.EntityFrameworkCore为Warning和Microsoft.EntityFrameworkCore.Database.Command为Information那么后者因为前缀更长在它覆盖的子类中会优先生效。利用这个规则你可以先给整个框架设置一个兜底级别再为特定模块放行更详细的日志。4.2 Scope的作用域魔法Scope是ILogger另一个容易被忽略但极为好用的能力。它的作用是把一组日志打上同一个标记通常用于把一次请求内的日志关联起来。HTTP请求的处理场景里中间件收到请求时创建一个Scope携带TraceId之后整个请求生命周期中的所有日志都会自动带上这个TraceId。用法很简单using (logger.BeginScope(new Dictionarystring, object { [TraceId] traceId, [UserId] userId })) { logger.LogInformation(开始处理订单 {OrderId}, orderId); // 这期间的日志都会自动携带 TraceId 和 UserId }Scope的价值在于它解决了一个很现实的问题一次请求可能会经过多个类、多个方法如果每个方法都手动传traceId参数代码会变得非常啰嗦。用Scope把上下文绑定到日志管道上所有被包裹的日志自动继承这些字段排查多服务调用链路的体验会好很多。需要注意的一点是Scope的开销比普通日志高所以不要在循环体里频繁创建Scope。如果确实需要在循环内记录多条带相同上下文的日志把Scope提到循环外面创建一次就够了。另外BeginScope返回的IDisposable一定要及时释放否则上下文可能会泄漏到其他日志里这个坑我在生产环境踩过排查起来非常隐蔽。4.3 手写一个自定义Provider虽然已有Provider很多但有时候你确实需要自己写一个——比如把日志写到某个内部消息队列或者转发到公司自研的监控平台。写一个Provider并没有想象中那么复杂核心是实现两个接口public class MyLoggerProvider : ILoggerProvider { public ILogger CreateLogger(string categoryName) { return new MyLogger(categoryName); } public void Dispose() { // 释放资源 } } public class MyLogger : ILogger { private readonly string _categoryName; public MyLogger(string categoryName) { _categoryName categoryName; } public IDisposable BeginScopeTState(TState state) null; public bool IsEnabled(LogLevel logLevel) logLevel LogLevel.Information; public void LogTState(LogLevel logLevel, EventId eventId, TState state, Exception exception, FuncTState, Exception, string formatter) { // 这里决定怎么写日志 var message formatter(state, exception); WriteToCustomTarget(logLevel, _categoryName, message, exception); } }然后注册到容器里builder.Logging.AddProvider(new MyLoggerProvider());这段代码里最需要留心的是Log方法的formatter参数。有些新手图省事直接自己拼消息字符串这是不对的——框架传进来的formatter已经帮你完成了消息模板的格式化而且只有在这个Logger确实启用的时候才会调用。用formatter还有一个额外好处当IsEnabled返回false时Log方法根本不会被调用你不需要在每个打日志的地方手动判断级别。我自己写自定义Provider时一般会把日志先扔进一个有界队列再由后台线程统一写入外部系统。原因很简单Log方法会被业务线程直接调用如果在这里直接发HTTP请求或者写库一旦外部系统变慢会拖垮正常业务。至于有界队列本身我用的是System.Threading.Channels实际效果很稳。5. 跑过一个生产项目后高频问题与排查心得现在聊聊我在生产项目里真正踩过的那些坑也算是一份问题速查表。5.1 日志太多导致磁盘打满这个问题我至少见过三次。症状很典型服务跑着跑着突然挂掉查了一下磁盘满了再一看日志目录好家伙一天写了20多个GB。原因基本逃不出这几类生产环境日志级别开得太低、某个第三方库疯狂打Debug日志、异常日志里把整个请求体或者大对象序列化了。解决方案分几步走。第一步把全局最低级别调到Information把框架类别的日志用Filter压到Warning第二步检查所有LogError调用确保第二个参数传的是异常对象而不是一个巨大的字符串第三步如果日志文件方案是自研的务必加上文件大小滚动和数量限制不要单个文件无限增长。我个人的习惯是在配置阶段就定好日志的“预算”每天最多写多少MB超出就自动滚动删除。这个预算应该写在团队的运维文档里而不是等磁盘满了再去救火。5.2 异步日志与性能日志是IO操作写多了自然影响性能。ILogger本身是同步接口但Provider内部可以做成异步。常见的做法有两种一是Provider内部用队列缓冲后台线程批量写入二是直接接入专门做异步日志的第三方库比如Serilog的Async扩展。不过我要提醒一点异步日志不是银弹。队列缓冲意味着日志写入有一定的延迟如果程序突然崩溃队列里还没写完的日志会丢失。在排查严重故障的时候你有可能恰恰丢了最后几秒的关键日志。所以对于Error和Critical级别的日志我会建议走同步写入或者至少保证它们不会被缓冲太久。这个取舍一定要提前想清楚别等出了事再后悔。另外日志本身也不要在热路径上做得太重。比如一个接口每秒调用几百次每次都打Information日志再快的IO也扛不住。我的原则是热路径上只记录必要信息能用级别过滤掉的就不打能合并成一条的不要打三条。日志打多了不仅占磁盘还会让真正重要的日志更难找。5.3 排查问题常用的几个临时小工具最后分享几个我排查日志问题时常用的临时手段都不需要改动业务代码。临时把日志级别调低可以通过配置中心或者环境变量完成比如在ASP.NET Core里用Logging__LogLevel__DefaultDebug这样的环境变量覆盖配置重启即生效如果已经写成了文件日志现场排查时用grep配合TraceId过滤单条请求链路比肉眼扫整个文件快得多。如果你用的是K8s或者Docker别忘了日志不只是写到容器里的文件更推荐让应用把日志输出到标准输出由容器运行时统一采集。这样你在kubectl logs里就能直接看到结构化日志搜索和过滤都方便很多。还有一个我经常用的技巧在本地复现问题的时候临时在Startup或者中间件里加一个只对自己IP生效的Debug日志开关。这样既不影响线上其它用户又能看到完整细节。这个做法说白了就是用环境变量或者配置中心控制一个动态开关在排查指定请求时打开详细日志查完马上关掉。我靠这个办法定位过好几个只有在特定请求参数下才会触发的诡异Bug比盲猜高效得多。最后再分享一个个人小习惯每次完成一个阶段的日志改造我会专门留出半小时“日志自测时间”把常见的几条业务链路手动走一遍然后打开日志文件或者日志平台按TraceId、按级别、按类别各查一遍确认输出符合预期才收工。这个习惯帮我提前拦下了好多“代码看着没问题但日志就是不对”的窘境也算是一个低成本高回报的收尾动作。

相关新闻

深入解析.NET ILogger:解锁稳健日志系统的核心机制

深入解析.NET ILogger:解锁稳健日志系统的核心机制

日志这件事,在.NET的开发圈子里一直是老生常谈的热门话题。以前我们用Log4Net或NLog,都是直接引用具体日志库,代码里到处是 LogManager.GetCurrentClassLogger() 这种静态调用。日志系统一旦绑定到具体实现,后面想换方案简直像脱…

2026/10/9 12:58:38 阅读更多 →
二次曲面分类记忆法:从方程结构快速判断曲面类型

二次曲面分类记忆法:从方程结构快速判断曲面类型

1. 为什么二次曲面总让人记不住1.1 从“背了忘、忘了背”的死循环说起但凡学过空间解析几何或者高等数学下册的人,大概率都有过这么一段经历:翻开课本,二次曲面那一章扑面而来的是椭球面、单叶双曲面、双叶双曲面、椭圆抛物面、双曲抛物面、二…

2026/10/9 12:58:38 阅读更多 →
AI科研味觉评估:TasteVal框架原理与五维诊断实践

AI科研味觉评估:TasteVal框架原理与五维诊断实践

1. 项目概述:这不是在给AI打分,而是在校准它的“味觉神经”最近在几个AI研究社区里,反复看到一个词被拎出来讨论:“TasteVal”。不是美食测评,也不是咖啡品鉴,而是把“taste”这个词硬生生拽进AI评估的实验…

2026/10/9 12:58:38 阅读更多 →

最新新闻

EMC必须认识的几种EMI频谱

EMC必须认识的几种EMI频谱

摘要:本文面向EMC行业的FAE和工程师,介绍五种常见EMI频谱的识别方法,包括电源包络、CLK时钟尖峰、电机杂波、PWM脉冲尖峰和高频信号包络,并给出对应的滤波优化方案。 对于刚接触或者从事 EMC 行业的 FAE 或者工程师,经…

2026/10/9 13:32:21 阅读更多 →
金吧台台球管理系统V:本地化场馆运营中枢部署指南

金吧台台球管理系统V:本地化场馆运营中枢部署指南

简介:金吧台台球管理系统V是一款面向中小型台球厅经营者及IT运维人员的商用级信息化管理软件,聚焦解决人工排桌低效、会员留存困难、库存损耗难控、财务对账繁琐等实际运营痛点。资源包共158个文件,含10个可执行程序(exe&#xff…

2026/10/9 13:32:21 阅读更多 →
从路由嵌套到前后台同构:管理后台路由架构落地实践

从路由嵌套到前后台同构:管理后台路由架构落地实践

从路由嵌套聊起,说说前后台同构的项目该怎么落地。最近在带一个前端小组做管理后台的改造,好几个同学都在问同一件事:为什么我们写路由的时候,非要把一堆页面分成“前台”和“后台”两拨来组织?明明都是路由配置&#…

2026/10/9 13:32:21 阅读更多 →
用GTK和gtkmm打造IPS补丁工具:格式、实现与避坑

用GTK和gtkmm打造IPS补丁工具:格式、实现与避坑

简介:这是一款基于GTK的IPS补丁工具,源自2014年的开源项目,用于将IPS补丁包应用到ROM文件,解决游戏汉化或修改时手动打补丁的繁琐问题,适合模拟器玩家、怀旧游戏爱好者以及C开发者学习参考。代码结构清晰,将…

2026/10/9 13:32:21 阅读更多 →
伪类和伪元素彻底讲清:::before与:befor选择器核心细节

伪类和伪元素彻底讲清:::before与:befor选择器核心细节

CSS 里有两类概念,看起来很像,用起来也经常混在一起:一类叫伪类,一类叫伪元素。再加上手滑把::before打成:befor,一条规则就这么静默失效,半天找不到原因。这篇就把最近被问得最多的一组问题整理清楚&#…

2026/10/9 13:32:21 阅读更多 →
CSS半透明实战:opacity与rgba的区别与正确选型

CSS半透明实战:opacity与rgba的区别与正确选型

"这个背景颜色怎么设成半透明,还不影响里面的文字?"——我最早开始写页面的时候,是直接往元素上甩一个 opacity: 0.5,觉得简单粗暴、效果立竿见影。直到被同事连着驳回两次,我才彻底明白:opacity…

2026/10/9 13:31:20 阅读更多 →

日新闻

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API这个话题,隔三差五就会在群里被翻出来讨论一次。上周还有个同事线上处理一个订单超时问题,排查到最后发现是ZonedDateTime序列化后时区丢了,用户在下单当天晚上看到的时间整整差了8个小时。这类问题几乎每个做Java开发的人都遇到过…

2026/10/9 0:00:49 阅读更多 →
EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

前几个月我手头有好几台机器需要互相访问:办公室台式机、家里 NAS、还有一台云主机。如果只是偶尔传个文件倒还好,问题是工作场景经常要在几处环境之间来回切换,每次都先登录跳板机再层层代理,实在折腾。我先后试过端口映射、自建…

2026/10/9 0:00:49 阅读更多 →
AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent 这个词在过去一年里被反复提及,但真正动手搭过一套能跑起来的 Agent 系统的人都知道,从"知道它是什么"到"让它稳定干活"之间隔着一整套工程决策。我前后参与过几个 Agent 项目的落地,从最初用现成框架拼装&…

2026/10/9 0:01:50 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:40 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 10:11:06 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 21:13:17 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 6:17:20 阅读更多 →