为什么pycharm输出的日志全部是红色!
日志一片红,不一定是报错。
我第一次碰到这个事,也以为程序炸了。PyCharm 控制台里刷出来的日志,info 是红的,warning 是红的,连我自己 print() 出来的东西都红了,看着跟线上雪崩一样,手都差点伸去改代码了。
结果最后发现,业务没毛病,日志框架也没毛病,红的是 stderr。
Python 里最常见就两条输出通道:
import sysprint("正常输出", file=sys.stdout)
print("看起来像报错,其实只是走了 stderr", file=sys.stderr)
在终端里,这俩很多时候看起来差不多。
但在 PyCharm 里,默认会把 stderr 渲染成红色,所以你会产生一种错觉:怎么我程序全在报错?
这事最容易出现在下面几种情况。
1.你自己把日志打到 stderr 了
很多人配 logging,随手就是一个 StreamHandler(),然后没细看它默认绑的是谁。
像这种:
import logginglogger = logging.getLogger("demo")
logger.setLevel(logging.DEBUG)
handler = logging.StreamHandler() # 默认就是 sys.stderr
formatter = logging.Formatter("%(levelname)s - %(message)s")
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.info("这条在 PyCharm 里大概率也是红的")
代码没问题。
红,是因为 StreamHandler() 默认输出到 sys.stderr,不是 sys.stdout。
改法也很直接:
import sys
import logginglogger = logging.getLogger("demo")
logger.setLevel(logging.DEBUG)
handler = logging.StreamHandler(sys.stdout)
formatter = logging.Formatter("%(asctime)s %(levelname)s %(message)s")
handler.setFormatter(formatter)
logger.handlers.clear()
logger.addHandler(handler)
logger.info("现在一般就不是红的了")
这类问题我一般先不看业务代码,先看日志初始化。 尤其是项目里封了一层 get_logger()、init_log() 这种工具方法的时候,八成就藏在那。
你没主动配 logging,框架替你打到 stderr 了
有些脚本你自己没配日志,但用了三方库、命令行工具、爬虫框架、测试框架,它们本身就喜欢往 stderr 打。
比如这种很常见:
import logginglogging.basicConfig(
level=logging.INFO,
format="%(levelname)s %(message)s"
)
logging.info("你以为是标准输出,其实默认还是 stderr")
basicConfig() 默认也是走 stderr。
想让它别红,直接指定 stream:
import sys
import logginglogging.basicConfig(
level=logging.INFO,
format="%(levelname)s %(message)s",
stream=sys.stdout
)
logging.info("这次走 stdout")
这个地方挺坑的。 很多人以为自己没手动写 stderr,那肯定不是输出流的问题。其实 logging 默认就已经帮你选了。
不是日志红,是进程报错信息混进来了
还有一种更像真的“全红”。
你程序里某个子进程、某个外部命令、某段异常堆栈正好在刷 stderr,PyCharm 就全给你标红了,看上去像整段日志都挂了。
比如:
import subprocessresult = subprocess.run(
["python", "-c", "import sys; print('hello'); print('warn', file=sys.stderr)"],
capture_output=True,
text=True
)
print("stdout:", result.stdout)
print("stderr:", result.stderr)
这时候你如果直接把 stderr 内容又 print 回控制台,颜色还是会乱。
我平时排这种,会先把两个流拆开看:
import subprocessp = subprocess.Popen(
["python", "task.py"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
out, err = p.communicate()
if out:
print("STDOUT >>>")
print(out)
if err:
print("STDERR >>>")
print(err)
先分清楚到底是谁在红,不然后面越看越像玄学。
PyCharm 运行配置里,把 stderr 单独高亮了
这个就不是 Python 的锅了,是 IDE 的展示习惯。
PyCharm 对标准错误流本来就会做醒目标记。 所以只要你的内容走了 stderr,哪怕只是普通提示,它也给你上红色。
这时候代码层面的修正还是那一套:
print()默认没问题,它走的是stdoutlogging默认常常有问题,它走的是stderr三方库和外部命令,很多也喜欢走 stderr
所以别一上来怀疑 PyCharm 抽风,先确认输出流。
我平时怎么快速定位
我一般会在入口脚本先插两行,先把现象钉死:
import sys
print("stdout check", file=sys.stdout)
print("stderr check", file=sys.stderr)
然后再看你那条“发红的日志”到底是跟哪边一起出来的。
如果还嫌不够直接,就把 handler 信息打出来:
import logginglogger = logging.getLogger()
for h in logger.handlers:
print(type(h), getattr(h, "stream", None))
现场一看,基本就知道是不是 StreamHandler(stderr) 了。
我自己写脚本,尤其是导数、清洗、巡检这类小工具,通常会把控制台日志和文件日志分开,不让控制台颜色影响判断。
import sys
import logginglogger = logging.getLogger("task")
logger.setLevel(logging.INFO)
logger.handlers.clear()
console = logging.StreamHandler(sys.stdout)
console.setLevel(logging.INFO)
console.setFormatter(logging.Formatter(
"%(asctime)s | %(levelname)s | %(message)s"
))
file_handler = logging.FileHandler("task.log", encoding="utf-8")
file_handler.setLevel(logging.INFO)
file_handler.setFormatter(logging.Formatter(
"%(asctime)s | %(name)s | %(levelname)s | %(message)s"
))
logger.addHandler(console)
logger.addHandler(file_handler)
logger.info("开始处理")
logger.warning("这条是 warning,但不该因为走 stderr 被染红")
logger.error("真报错了就让它按级别报错")
这样至少看控制台的时候,颜色和严重程度更接近,不会被 IDE 的 stderr 渲染带偏。
PyCharm 里日志全红,最常见的原因不是程序全报错了,是你的日志走了 stderr。
重点看这两个地方就够了:
logging.StreamHandler() # 默认 stderr
logging.basicConfig(...) # 默认 stderr
把它们改成 sys.stdout,十有八九就清净了:
logging.StreamHandler(sys.stdout)
这事不算大坑,但很烦。 因为它不影响程序跑,就是特别影响你判断现场。你盯着一屏红字看半天,最后发现只是输出流选错了,这种感觉,挺像白查半小时日志。