在 C# 里记日志,用 Console.WriteLine() 或第三方库------Serilog、NLog、log4net,配置复杂但功能强大。
在 Python 里记日志,用 logging 模块------内置的,开箱即用,配置灵活。
C# 的日志生态很丰富,但选择太多反而让人纠结。Python 的 logging 模块虽然简单,但该有的功能都有。
Python 的 logging 模块虽然简单,但该有的功能一个不少------开箱即用才是王道。
基础用法
C# 版本:
// 最简单的日志
Console.WriteLine("这是一条日志");
// 使用内置的 Trace/Debug
Trace.WriteLine("跟踪信息");
Debug.WriteLine("调试信息");
// 使用第三方库(如 Serilog)
using var log = new LoggerConfiguration()
.WriteTo.Console()
.CreateLogger();
log.Information("这是一条信息日志");
log.Warning("这是一条警告日志");
log.Error("这是一条错误日志");
Python 版本:
import logging
# 配置日志
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
# 基础日志
logging.debug("这是调试信息")
logging.info("这是信息日志")
logging.warning("这是警告日志")
logging.error("这是错误日志")
logging.critical("这是严重错误")
对比一下:
| 级别 | C# | Python |
|---|---|---|
| 调试 | Debug.WriteLine() |
logging.debug() |
| 信息 | log.Information() |
logging.info() |
| 警告 | log.Warning() |
logging.warning() |
| 错误 | log.Error() |
logging.error() |
| 严重 | log.Fatal() |
logging.critical() |
Python 的 logging 模块比 C# 的 Console.WriteLine() 更专业------有级别、有格式、有处理器。
Logger 对象
C# 版本(Serilog):
// 创建 Logger
var logger = new LoggerConfiguration()
.WriteTo.Console()
.WriteTo.File("logs/app.log", rollingInterval: RollingInterval.Day)
.CreateLogger();
// 使用 Logger
logger.Information("用户 {UserId} 登录", userId);
logger.Error(ex, "处理请求时出错");
Python 版本:
import logging
# 创建 Logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# 添加处理器
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
file_handler = logging.FileHandler('app.log', encoding='utf-8')
file_handler.setLevel(logging.DEBUG)
# 设置格式
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
console_handler.setFormatter(formatter)
file_handler.setFormatter(formatter)
# 添加处理器到 Logger
logger.addHandler(console_handler)
logger.addHandler(file_handler)
# 使用 Logger
logger.info("用户 %s 登录", user_id)
logger.error("处理请求时出错", exc_info=True)
| 特性 | C#(Serilog) | Python |
|---|---|---|
| 创建方式 | new LoggerConfiguration() |
logging.getLogger() |
| 输出到控制台 | .WriteTo.Console() |
StreamHandler() |
| 输出到文件 | .WriteTo.File() |
FileHandler() |
| 输出到数据库 | .WriteTo.MSSqlServer() |
自定义 Handler |
| 格式化 | "{UserId}" |
%(name)s |
Python 的 Handler 比 C# 的 Sink 更灵活------可以自定义处理器。
日志格式
C# 版本(Serilog):
var logger = new LoggerConfiguration()
.WriteTo.Console(outputTemplate:
"[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}")
.CreateLogger();
Python 版本:
import logging
# 自定义格式
formatter = logging.Formatter(
fmt='[%(asctime)s] %(levelname)-8s %(message)s',
datefmt='%H:%M:%S'
)
# 使用格式
handler = logging.StreamHandler()
handler.setFormatter(formatter)
常用格式化参数:
| 参数 | 说明 | C# 对应 |
|---|---|---|
%(asctime)s |
时间戳 | {Timestamp} |
%(levelname)s |
日志级别 | {Level} |
%(name)s |
Logger 名称 | {SourceContext} |
%(message)s |
日志消息 | {Message} |
%(filename)s |
文件名 | {FileName} |
%(lineno)d |
行号 | {LineNumber} |
%(funcName)s |
函数名 | {MethodName} |
实际场景:Web 应用日志
C# 版本(ASP.NET Core):
// appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
// Program.cs
builder.Host.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.AddConsole();
logging.AddFile("logs/app-{Date}.txt");
});
Python 版本(Flask):
import logging
from logging.handlers import RotatingFileHandler
from flask import Flask
app = Flask(__name__)
# 配置日志
if not app.debug:
# 文件日志(滚动)
file_handler = RotatingFileHandler(
'logs/app.log',
maxBytes=10240000, # 10MB
backupCount=10
)
file_handler.setFormatter(logging.Formatter(
'%(asctime)s %(levelname)s: %(message)s '
'[in %(pathname)s:%(lineno)d]'
))
file_handler.setLevel(logging.INFO)
app.logger.addHandler(file_handler)
# 控制台日志
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG)
app.logger.addHandler(console_handler)
app.logger.setLevel(logging.INFO)
app.logger.info('应用启动')
日志处理器(Handler)
C# 的 Sink 和 Python 的 Handler:
| 处理器 | C#(Serilog) | Python |
|---|---|---|
| 控制台 | .WriteTo.Console() |
StreamHandler() |
| 文件 | .WriteTo.File() |
FileHandler() |
| 滚动文件 | .WriteTo.File(rollingInterval:) |
RotatingFileHandler() |
| HTTP | .WriteTo.HTTP() |
HTTPHandler() |
| SMTP(邮件) | .WriteTo.Email() |
SMTPHandler() |
| Syslog | .WriteTo.Syslog() |
SysLogHandler() |
Python 的 RotatingFileHandler 比 C# 的滚动文件更灵活------可以设置文件大小和备份数量。
性能考虑
C# 版本:
// Serilog 是异步的,性能较好
var logger = new LoggerConfiguration()
.WriteTo.Async(a => a.Console())
.CreateLogger();
// 或者用 Microsoft.Extensions.Logging
services.AddLogging(builder =>
{
builder.AddConsole();
builder.SetMinimumLevel(LogLevel.Information);
});
Python 版本:
import logging
from logging.handlers import QueueHandler, QueueListener
from queue import Queue
# 异步日志(Python 3.12+)
queue = Queue()
queue_handler = QueueHandler(queue)
# 配置处理器
handler = logging.StreamHandler()
listener = QueueListener(queue, handler)
listener.start()
# 使用
logger = logging.getLogger(__name__)
logger.addHandler(queue_handler)
logger.info("异步日志")
Python 3.12+ 支持异步日志,但 C# 的 Serilog 在异步方面更成熟。
设计哲学
C# 的日志是"多选一"------Serilog、NLog、log4net、Microsoft.Extensions.Logging,选择丰富但配置复杂。
Python 的日志是"内置款"------logging 模块开箱即用,简单够用,扩展灵活。
C# 的日志像是"超市购物",品牌众多,任你挑选; Python 的日志像是"便利店",商品不多,但该有的都有。
更深层的原因:
-
C# 的日志生态是社区驱动的,每个库都有自己的设计理念
-
Python 的日志是标准库的,遵循"一种方式做一件事"的哲学
迁移指南:C# 开发者最容易犯的错
-
忘记配置级别:默认只显示 WARNING 及以上
-
忘记添加 Handler:没有 Handler,日志不会输出
-
**用
print()代替logging**:print()没有级别、没有格式 -
忘记编码 :文件日志需要指定
encoding='utf-8' -
**过度使用
logging.debug()**:生产环境应该用 INFO 或更高
坑点提醒
默认级别是 WARNING------需要手动设置:
import logging
# 默认只显示 WARNING 及以上
logging.info("这不会显示") # 不输出
logging.warning("这会显示") # 输出
# 设置级别
logging.basicConfig(level=logging.DEBUG)
logging.info("现在会显示了") # 输出
Handler 需要单独添加------Logger 本身不输出:
import logging
logger = logging.getLogger(__name__)
# 没有 Handler,不会输出任何内容!
# 添加 Handler
handler = logging.StreamHandler()
logger.addHandler(handler)
logger.info("现在会输出了")
多个 Logger 可能重复输出------注意 Logger 层级:
import logging
# 父 Logger
parent = logging.getLogger('app')
parent.addHandler(logging.StreamHandler())
# 子 Logger
child = logging.getLogger('app.module')
# 子 Logger 会继承父 Logger 的 Handler
child.info("这会输出两次!")
一句话总结
Python 的
logging模块是"内置款"------简单够用,开箱即用,比 C# 的Console.WriteLine()专业得多。
📦 示例代码:C# 转 Python 全系列配套练习代码(含 48 章示例)
💬 欢迎点赞、收藏、转发,你的支持是我持续创作的动力!