Python 解决logging功能使用过程中遇到的一个问题

现象:

生产中心进行拷机任务下了300个任务,过了一阵时间后发现任务不再被调度起来,查看后台日志发现日志输出停在某个时间点。

分析:

1、首先确认进程存在并没有dead。

2、然后用strace –p看了一下进程,发现进程卡在futex调用上面,应该是在锁操作上面出问题了。

3、用gdb attach进程ID,用py-bt查看一下堆栈,发现堆栈的信息大致为:sig_handler(某个信号处理函数)->auroralogger(自定义的日志函数)->logging(python的logging模块)->threading.acquire(获取锁)。从gdb的bt信息基本验证了上面的猜想,应该是出现了死锁。

4、Python的logging模块本身肯定不会有死锁的这种bug有可能出问题的就是我们的使用方式,看python中logging模块的doc,发现有一个有一个Thread Safety的章节,内容很简单但是也一下就解释了我遇到的这个问题,内容如下:

The logging module is intended to be thread-safe without any special work needing to be done by its clients. It achieves this though using threading locks; there is one lock to serialize access to the module's shared data, and each handler also creates a lock to serialize access to its underlying I/O.

If you are implementing asynchronous signal handlers using the signal module, you may not be able to use logging from within such handlers. This is because lock implementations in the threading module are not always re-entrant, and so cannot be invoked from such signal handlers.

第一部分是说logging是线程安全的,通过threading的lock对公用的数据进行了加锁。

第二部分特意提到了在异步的信号处理函数中不能使用logging模块,因为threading的lock机制是不支持重入的。

这样就解释了上面我遇到的死锁问题,因为我在信号处理函数中调用了不可以重入的logging模块。

线程安全和可重入:

从上面的logging模块来看线程安全和可重入不是等价的,那么这两个概念之间有什么联系、区别呢?

1、可重入函数:从字面意思来理解就是这个函数可以重复调用,函数被多个线程乱序执行甚至交错执行都能保证函数的输出和函数单独被执行一次的输出一致。也就是说函数的输出只决定于输入。

线程安全函数:函数可以被多个线程调用,并且保证不会引用到错误的或者脏的数据。线程安全的函数输出不仅仅依赖于输入还可能依赖于被调用时的顺序。

2、可重入函数和线程安全函数之间有一个最大的差异是:是否是异步信号安全。可重入函数在异步信号处理函数中可以被安全调用,而线程安全函数不保证可以在异步信号处理函数中被安全调用。

上面我们遇到的loggin模块就是非异步信号安全的,在主线程中我们正在使用log函数而log函数调用了threading.lock来获取到了锁,此时一个异步信号产生程序跳转到信号处理函数中,信号处理函数又正好调用了log函数,因为前一个被调用的log函数还未释放锁,最后就形成了一个死锁。

1、可重入函数必然是线程安全函数和异步信号安全函数,线程安全函数不一定是可重入函数。

总结:

异步信号处理函数中一定要尽可能的功能简单并且不能调用不可重入的函数。

Python loggin模块是线程安全但是是不可重入的。

补充:Python—logging模块使用教程

简单用法

日志等级

级别 何时使用
DEBUG 细节信息,仅当诊断问题时适用。
INFO 确认程序按预期运行
WARNING 表明有已经或即将发生的意外(例如:磁盘空间不足)。程序仍按预期进行
ERROR 由于严重的问题,程序的某些功能已经不能正常执行
CRITICAL 严重的错误,表明程序已不能继续执行

控制台输出日志

import logging
logging.warning('Watch out!')
logging.info('I told you so') 

将日志保存到文件并且设置时间和输出格式

import logging
# 保存文件为example.log,记录等级为DEBUG,即只记录DENBUG及以上的日志
# 输出格式为 2019-19-06 18:47:06 - WARNING - And this, too
logging.basicConfig(
  filename='example.log',
  filemode='w',
  level=logging.DEBUG,
  format='%(asctime)s - %(levelname)s - %(message)s',
  datefmt='%Y-%d-%d %H:%M:%S'
)
logging.debug('This message should go to the log file')
logging.info('So shoul this')
logging.warning('And this, too')

参数解释

filename日志文件路径

filemode记录日志文件的模式,w为每次启动程序都创建一个全新的文件记录, a表示追加到文件末尾, 默认为a

level记录日志的等级

format日志输出的格式

datefmt日志输出时间的格式

使用配置文件配置日志

[loggers]
# 配置日志对象名, 默认为root
keys=root, poj
[handlers]
# 日志配置名对象名
keys=writeFileHandlers
[formatters]
# 日志输出格式对象名
keys=writeFileFormatters
[logger_root]
level=DEBUG
handlers=writeFileHandlers
[logger_poj]
level=DEBUG
handlers=writeFileHandlers
qualname=writeFileFormatters
propagate=0
[logger_leetcode]
level=DEBUG
handlers=writeFileHandlers
qualname=writeFileFormatters
propagate=0
[handler_writeFileHandlers]
# 设置writeFileHandlers对象的配置
class=FileHandler
level=DEBUG
formatter=writeFileFormatters
# 记录在文件中,以追加的形式
args=("demo.log", "a")
[formatter_writeFileFormatters]
设置writeFileHandlers对象的输出配置
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
datefmt=%Y-%d-%m %H:%M:%S

使用配置文件

import logging.config
# 加载配置文件
logging.config.fileConfig('logging.conf')
# 获取日志对象名为poj的
logger = logging.getLogger("poj")
logger.debug('This message should go to the log file')
logger.info('So shoul this')
logger.warning('And this, too')

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。如有错误或未考虑完全的地方,望不吝赐教。

(0)

相关推荐

  • python 日志模块logging的使用场景及示例

    前言 日志是对于软件执行所发生的事件的一种追踪记录方式.日常使用过程中对代码执行的错误和问题会进行查看日志来分析定位问题所在.平常编写代码以及调试也经常用到.通常的新手的做法是直接print打印,但是打印的结果只在控制台显示.今天我们学习一种高级的日志打印和记录模块logging. logging提供了一系列的函数,它们是debug(), info(), warning(), error(), 和critical(). 他们的使用场景请看下表 你想要执行的任务 此任务的最好的工具 对于命令行或程

  • python 实现logging动态变更输出日志文件名

    python作为一门非常容易上手的脚本语言,日志输出更是简单,logging模块,简单的设置配置和属性,就能实现到控制台输出日志,在basicConfig()设置文件名,就能够将日志信息写入文件,简直是简单到不能再简单. 最近在项目中就遇到一个日志问题,使用python编写的服务程序一直运行,连续处理一些任务,每个任务的关键信息都需要输出到文件中,便于维护人员查看,可是对于简单实用logging来说,日志写入文件非常简单,由于服务程序连续运行,一直向一个文件记录日志信息有些不妥,有常识的开发人员

  • Python日志打印里logging.getLogger源码分析详解

    实践环境 WIN 10 Python 3.6.5 函数说明 logging.getLogger(name=None) getLogger函数位于logging/__init__.py脚本 源码分析 _loggerClass = Logger # ...略 root = RootLogger(WARNING) Logger.root = root Logger.manager = Manager(Logger.root) # ...略 def getLogger(name=None): "&quo

  • 解决python logging遇到的坑 日志重复打印问题

    python 中 logging模块 假如遇到 多线程 或者 多进程 或者在web框架中自定义logging的话(一个请求就是一个独立的线程)非常容易重复打印日志 和造成内存崩溃,所以: 解决方法如下: 重写日志方法 用类: class Log(): import logging def __init__(self): self.logger = logging.getLogger(__name__) # 以下三行为清空上次文件 # 这为清空当前文件的logging 因为logging会包含所有

  • python (logging) 日志按日期、大小回滚的操作

    描述: 日志按日期.大小回滚 代码: # -*- coding: utf-8 -*- import os import logging.handlers log_dir = os.path.dirname(os.path.abspath(__file__)) + os.sep + 'logs' if not os.path.isdir(log_dir): os.makedirs(log_dir) # CONSTANT VARIABLES MODULE_NAME = 'my_module' LOG

  • Python如何使用logging为Flask增加logid

    我们为了问题定位,常见做法是在日志中加入 logid,用于关联一个请求的上下文.这就涉及两个问题:1. logid 这个"全局"变量如何保存传递.2. 如何让打印日志的时候自动带上 logid(毕竟不能每个打日志的地方都手动传入) logid保存与传递 传统做法就是讲 logid 保存在 threading.local 里面,一个线程里都是一样的值.在 before_app_request 就生成好,logid并放进去. import threading   from blueprin

  • Python 解决logging功能使用过程中遇到的一个问题

    现象: 生产中心进行拷机任务下了300个任务,过了一阵时间后发现任务不再被调度起来,查看后台日志发现日志输出停在某个时间点. 分析: 1.首先确认进程存在并没有dead. 2.然后用strace –p看了一下进程,发现进程卡在futex调用上面,应该是在锁操作上面出问题了. 3.用gdb attach进程ID,用py-bt查看一下堆栈,发现堆栈的信息大致为:sig_handler(某个信号处理函数)->auroralogger(自定义的日志函数)->logging(python的logging

  • 解决pytorch GPU 计算过程中出现内存耗尽的问题

    Pytorch GPU运算过程中会出现:"cuda runtime error(2): out of memory"这样的错误.通常,这种错误是由于在循环中使用全局变量当做累加器,且累加梯度信息的缘故,用官方的说法就是:"accumulate history across your training loop".在默认情况下,开启梯度计算的Tensor变量是会在GPU保持他的历史数据的,所以在编程或者调试过程中应该尽力避免在循环中累加梯度信息. 下面举个栗子: 上代

  • 解决Android加壳过程中mprotect调用失败的原因分析

    目录 问题原由 调用mprotect修改内存失败的现象 mprotect调用失败的原因分析 两种可行的解决方案 小结 问题原由 函数抽取壳是当前最为流行的DEX加壳方式之一,这种加壳方式的主要流程包含两个步骤:一.将DEX中需要保护的函数指令置空(即抽取函数体):二.在应用启动的过程中,HOOK 类的加载过程,比如ClassLinker::LoadMethod函数,然后及时回填指令. 笔者在实现抽取壳的过程中遇到了一个问题,即在步骤二回填指令之前,需要先调用mprotect将目标内存设置为“可写

  • 详解关于Angular4 ng-zorro使用过程中遇到的问题

    写在前面 由于现在网络上Angular 4的相关技术文档不是很充分,我写出这个采坑的记录文档,一方面是想给自己在项目中遇到的各种问题与个人的理解记录下来,另一方面也想着某些坑大家可能也会遇到,也可以给道友做一个参考.文档中的很多地方多有不足,后期我会慢慢完善,也希望道友们能够及时指出文档中不正确的与可以优化的地方. 我计划将该帮助文档分为4个章节: 章节一: 关于angular 4 + ng-zorro在基础布局与模块拆分上的一些问题与操作步骤 章节二: angular 4 引入路由=> 组件模

  • 关于maven使用过程中无法导入依赖的一些总结

    目录 maven使用过程中无法导入依赖的一些总结 maven不自动导入依赖问题 解决办法 maven使用过程中无法导入依赖的一些总结 作为一名java开发的新手,在学习中难免遇见各种问题,在此总结一下. 在使用maven过程中总是碰见某些依赖导不进去的问题,本人使用的是idea2017.maven3.2版本,通过网上搜索和自己的经验归纳为一下几点: 1.settings.xml文件中远程仓库地址的设置 在maven仓库的配置文件中,一般设置远程仓库地址为阿里云的私服,国外的网站也可以就是比较慢,

  • python解决Fedora解压zip时中文乱码的方法

    前言 很多时候在windows下压缩文件没问题,但是到了Linux下,出现乱码,很常见.以前在Ubuntu下,用`unzip -O GBK filename.zip` 就可以搞定. 换了Fedora后,暂时没发现乱码的压缩文件.晚上下载一本书的光盘,又碰到了乱码.尝试之前的方法没成功.看了下unzip的help,没-O那个参数了== 刚好找到一个用python解决的办法,分享下. 新建一个`.py`后缀的文件,直接复制粘贴代码: #!/usr/bin/env python # -*- codin

  • Python结巴中文分词工具使用过程中遇到的问题及解决方法

    本文实例讲述了Python结巴中文分词工具使用过程中遇到的问题及解决方法.分享给大家供大家参考,具体如下: 结巴分词是Python语言中效果最好的分词工具,其功能包括:分词.词性标注.关键词抽取.支持用户词表等.这几天一直在研究这个工具,在安装与使用过程中遇到一些问题,现在把自己的一些方法帖出来分享一下. 官网地址:https://github.com/fxsjy/jieba 1.安装. 按照官网上的说法,有三种安装方式, 第一种是全自动安装:easy_install jieba 或者 pip

  • jupyter notebook 使用过程中python莫名崩溃的原因及解决方式

    最近在使用 Python notebook时老是出现python崩溃的现象,如下图,诱发的原因是"KERNELBASE.dll",异常代码报"40000015". 折腾半天,发现我启动notebook时是用自定义startup.bat方式方式启动的,bat文件的内容为 start C:\Anaconda3\python.exe "C:/Anaconda3/Scripts/jupyter-notebook-script.py" 平时双击这个bat文

  • 解决Python httpx 运行过程中无限阻塞的问题

    目录 Python httpx 运行过程中无限阻塞 1.通过 pm2 部署脚本 2.通过装饰器给函数设置一个最大执行超时时间 python爬虫httpx的用法 请求方式 Python httpx 运行过程中无限阻塞 requests 模块只支持 http1,在遇到 http2 的数据接口的时候(某乎的搜索接口),需要采用支持http2 请求的模块(如 httpx.hyper). 本文是针对 httpx 在请求数据时,出现无限阻塞问题的一些处理方法. httpx 的 timeout 有 bug,会

  • python logging日志打印过程解析

    一. 基础使用 1.1 logging使用场景 日志是什么?这个不用多解释.百分之九十的程序都需要提供日志功能.Python内置的logging模块,为我们提供了现成的高效好用的日志解决方案.但是,不是所有的场景都需要使用logging模块,下面是Python官方推荐的使用方法: 任务场景 最佳工具 普通情况下,在控制台显示输出 print() 报告正常程序操作过程中发生的事件 logging.info()(或者更详细的logging.debug()) 发出有关特定事件的警告 warnings.

随机推荐