python报错提示以及logger的一些应用

news2024/12/24 21:38:48

本篇是拆解这篇【python︱函数、for、if、name、迭代器、防范报错、类定义、装饰器、argparse模块、yield 】 将报错 + logger提示拿出来

文章目录

  • 1、防范报错
    • 1.1 assert 断言
  • 2 try...except...
    • 报错并提示异常信息
    • 优雅的异常报错:suppress
  • 3、报错日志记录:Logger.exception
    • 3.1 logger - basicConfig 常规存储
    • 3.2 常规:logging + handlers + TimedRotatingFileHandler
        • 延伸错误信息一起载入log:
      • 延申错误二:logger无法显示中文
    • 3.3 用.yaml文件配置Log
  • 4、with...as...
  • 5 主动发出报错raise
  • 6 Logger好用的新库:loguru
    • 6.1 文件保存
    • 6.2 文件保存与删除
    • 6.3 常规用法 + 异常函数追踪 - 非常给力!!


1、防范报错

1.1 assert 断言

Python的assert是用来检查一个条件,如果它为真,就不做任何事。如果它为假,则会抛出AssertError并且包含错误信息。例如:

py> x = 23
py> assert x > 0, "x is not zero or negative"
py> assert x%2 == 0, "x is not an even number"
Traceback (most recent call last):
File "", line 1, in 
AssertionError: x is not an even number

类似R中的stopifnot

参考博客:Python 中何时使用断言?
.

2 try…except…

两种将报错异常展示的方式:

# 第一种
try:
    0/0
except Exception as e:
    print (e)
>>> division by zero

# 第二种,更加全面
import traceback
import sys
try:
    0/0
except:
    traceback.print_exc()
>>> 
Traceback (most recent call last):
  File "<ipython-input-4-17cf35f30609>", line 4, in <module>
    0/0
ZeroDivisionError: division by zero

try:
    f = open('xxx')
except:
    print 'fail to open'
    exit(-1)

如果try中open不出来,那么就except返回相应的内容“fail to open”

try:
<语句>        #运行别的代码
except <名字>:
<语句>        #如果在try部份引发了'name'异常
except <名字>,<数据>:
<语句>        #如果引发了'name'异常,获得附加的数据
else:
<语句>        #如果没有异常发生

参考
看一个案例:

try:
    print('I am sure no exception is going to occur!')
except Exception:
    print('exception')
else:
    # 这里的代码只会在try语句里没有触发异常时运行,
    # 但是这里的异常将 *不会* 被捕获
    print('This would only run if no exception occurs. And an error here '
          'would NOT be caught.')
finally:
    print('This would be printed in every case.')

# Output: I am sure no exception is going to occur!
# This would only run if no exception occurs.
# This would be printed in every case.

报错并提示异常信息

来源:Python中获取异常(Exception)信息
1、str(e)

返回字符串类型,只给出异常信息,不包括异常信息的类型,如1/0的异常信息

‘integer division or modulo by zero’
2、repr(e)

给出较全的异常信息,包括异常信息的类型,如1/0的异常信息

“ZeroDivisionError(‘integer division or modulo by zero’,)”
3、e.message

获得的信息同str(e)

4、采用traceback模块

需要导入traceback模块,此时获取的信息最全,与python命令行运行程序出现错误信息一致。使用traceback.print_exc()打印异常信息到标准错误,就像没有获取一样,或者使用traceback.format_exc()将同样的输出获取为字符串。你可以向这些函数传递各种各样的参数来限制输出,或者重新打印到像文件类型的对象。

try:
    1/0
except Exception, e:
    print 'str(Exception):\t', str(Exception)
    print 'str(e):\t\t', str(e)
    print 'repr(e):\t', repr(e)
    print 'e.message:\t', e.message
    print 'traceback.print_exc():'; traceback.print_exc()
    print 'traceback.format_exc():\n%s' % traceback.format_exc()

或者:

def this_fails():
    x = 1/0

try:
    this_fails()
except :
    print('Handling run-time error:')
    raise
print(1)

优雅的异常报错:suppress

但是常碰到的情形是这样的:

• 我们知道这个异常有可能发生
• 我们不关心这个异常,如果发生了,什么也不用处理,直接忽略就好

如果要处理这种情形的异常,那么不必使用 try-except,Python 内置的 contextlib 库提供了一个函数,叫 suppress,是处理这种异常更优雅的方式,Pythonista 一定要尝试使用。

# 单个非0报错
from contextlib import suppress

nums = [3,0,3,0,3]
result = 0
for num in nums:
    with suppress(ZeroDivisionError):
        result += 1/num
print(result) # 1.0

# 免疫所有报错
for num in nums:
    with suppress(Exception):
        result += 1/num

# 别这么写
result = 0 
nums = [3,0,3,0,3]
with suppress(Exception):
    for num in nums:
        result += 1/num

print(result) # 0.3333333333333333

3、报错日志记录:Logger.exception

以ERROR级别记录日志消息,异常跟踪信息将被自动添加到日志消息里。Logger.exception通过用在异常处理块中,如:
来源:Python模块学习:logging 日志记录

import logging
logging.basicConfig(filename = os.path.join(os.getcwd(), 'log.txt'), level = logging.DEBUG)
log = logging.getLogger('root')
try:
    a===b
except:
    log.exception('exception') #异常信息被自动添加到日志消息中

就会在指定目录里面,载入到Log.txt之中

来看看在Log中显示如下:

ERROR:root:exception
Traceback (most recent call last):
  File "test.py", line 12, in <module>
    a==b
NameError: name 'a' is not defined

所以,在 log.exception()可以简单定义一些关键词来帮助定位问题所在。

3.1 logger - basicConfig 常规存储

来源:python logging模块打印log到指定文件

import logging
import unittest
class lgtest(unittest.TestCase):
    logging.basicConfig(filename='../LOG/'+__name__+'.log',format='[%(asctime)s-%(filename)s-%(levelname)s:%(message)s]', level = logging.DEBUG,filemode='a',datefmt='%Y-%m-%d%I:%M:%S %p')

    def test(self):

        logging.error("这是一条error信息的打印")
        logging.info("这是一条info信息的打印")
        logging.warning("这是一条warn信息的打印")
        logging.debug("这是一条debug信息的打印")
if __name__=='__main__':
    unittest.main()
  • Filename:指定路径的文件。这里使用了+—name—+是将log命名为当前py的文件名
  • Format:设置log的显示格式(即在文档中看到的格式)。分别是时间+当前文件名+log输出级别+输出的信息
  • Level:输出的log级别,优先级比设置的级别低的将不会被输出保存到log文档中
  • Filemode: log打开模式
    • a:代表每次运行程序都继续写log。即不覆盖之前保存的log信息。
    • w:代表每次运行程序都重新写log。即覆盖之前保存的log信息

3.2 常规:logging + handlers + TimedRotatingFileHandler

参考:Python + logging 输出到屏幕,将log日志写入文件
参考:python中logging模块下篇

# 信息写入log
import logging
from logging import handlers
class Logger(object):
    level_relations = {
        'debug':logging.DEBUG,
        'info':logging.INFO,
        'warning':logging.WARNING,
        'error':logging.ERROR,
        'crit':logging.CRITICAL
    }#日志级别关系映射

    def __init__(self,filename,level='info',when='D',backCount=15,\
                 fmt='%(asctime)s - %(levelname)s: %(message)s'):
        self.logger = logging.getLogger(filename)   # 创建log文件
        format_str = logging.Formatter(fmt)#设置日志格式
        self.logger.setLevel(self.level_relations.get(level))#设置日志级别
        if not self.logger.handlers:
            sh = logging.StreamHandler()  # 初始化 1 ,往屏幕上输出
            sh.setFormatter(format_str)   #  设置屏幕上显示的格式
            th = handlers.TimedRotatingFileHandler(filename=filename,when=when,\
                                                   backupCount=backCount,encoding='utf-8')
            
            th.setFormatter(format_str)#设置文件里写入的格式
            self.logger.addHandler(sh) #把对象加到logger里
            self.logger.addHandler(th)
if __name__ == '__main__':
    log = Logger('all.log',level='debug')
    log.logger.debug('debug')
    log.logger.info('info')
    log.logger.warning('警告')
    log.logger.error('报错'', exc_info=True)
    log.logger.critical('严重')
    Logger('error.log', level='error').logger.error('error')

屏幕上的结果如下:

2018-03-13 21:06:46,092 - DEBUG: debug
2018-03-13 21:06:46,092 - INFO: info
2018-03-13 21:06:46,092- WARNING: 警告
2018-03-13 21:06:46,099 - ERROR: 报错
2018-03-13 21:06:46,099- CRITICAL: 严重
2018-03-13 21:06:46,100 - ERROR: error

由于when=D,新生成的文件名上会带上时间,如下所示。
在这里插入图片描述

其中:

  • level_relations ,代表日志级别,默认等级是WARNING,这意味着仅仅这个等级及以上的才会反馈信息,除非logging模块被用来做其它事情。

    • 日志级别: debug < info < warning < error < critical
  • TimedRotatingFileHandler - 按照时间自动分割日志文件

  • interval是时间间隔

  • when是间隔的时间单位,单位有以下几种:

    • S 秒
    • M 分
    • H 小时、
    • D 天、
    • W 每星期(interval==0时代表星期一)
    • midnight 每天凌晨
  • backupCount 是保留日志个数。默认的0是不会自动删除掉日志。若设10,则在文件的创建过程中库会判断是否有超过这个10,若超过,则会从最先创建的开始删除。

  • exc_info,True,代表把错误信息也保存下来,默认是False,不保存

同时,
你会发现如果不设置if not self.logger.handlers:,那么会出现,重复写日志问题。问题出在,他会不断往log.logger.handlers添加handlers,上限是三个,就会出现:
第一条记录写一次,第二条记录写两次,第三条记录写三次。
(解决方案来自:python logging 重复写日志问题)
原理在于,如果self.logger.handlers已经有类了,那么就不要额外添加了。

# 正常的self.logger.handlers长什么样子:
[<logging.StreamHandler at 0x12eba1e3128>,
 <logging.handlers.TimedRotatingFileHandler at 0x12eba1e3160>]

# 不正常的self.logger.handlers长什么样子:
[<logging.StreamHandler at 0x12eba1e3128>,
 <logging.handlers.TimedRotatingFileHandler at 0x12eba1e3160>,
 [<logging.StreamHandler at 0x12eba1e3128>,
 <logging.handlers.TimedRotatingFileHandler at 0x12eba1e3160>,]

延伸错误信息一起载入log:

import logging
logging.basicConfig(level=logging.INFO,
                   format='%(asctime)s  %(message)s',
                   datefmt='%a, %d %b %Y %H:%M:%S +0000',
                   filename='my.log')

logging.info('this is a info')
try:
    do
except Exception:
    logging.error('There are something wrong', exc_info=True)

logging.info('continue')


# 报错信息暴露
Sun, 01 Jul 2018 21:10:53 +0000  There are something wrong
Traceback (most recent call last):
  File "learn.py", line 9, in <module>
    do
NameError: name 'do' is not defined
Sun, 01 Jul 2018 21:10:53 +0000  continue

延申错误二:logger无法显示中文

stream.write(msg)
UnicodeEncodeError: 'ascii' codec can't encode character '\ufffd' in position 363: ordinal not in range(128)

参考:https://github.com/EasyEngine/easyengine/issues/843

解决,其实是系统缺少UTF-8组件,需要载入:

This worked for me:

sudo locale-gen en_US.UTF-8
export LANG=en_US.UTF-8

From: http://askubuntu.com/questions/393638/unicodedecodeerror-ascii-codec-cant-decode-byte-0x-in-position-ordinal-n

3.3 用.yaml文件配置Log

python中logging模块下篇

我们不仅可以通过python代码进行logging配置,而且可以通过写一个yaml文件进行配置,每次需要用logging时只要调用这个文件就配置完成。

config.yaml文件内容如下

version: 1
formatters:
  simple:
    format: "%(message)s"
  more:
    format: "%(asctime)s - %(levelname)s - %(message)s"
handlers:
  console:
    class : logging.StreamHandler
    formatter: simple
    level: INFO
    stream: ext://sys.stdout
  file:
    class: logging.FileHandler
    formatter: more
    level: DEBUG
    filename: debug.log
loggers:
  mainlogger:
    level: DEBUG
    handlers: [console, file]
  root:
    level: DEBUG
    handlers: [console]

main.py文件中编写代码如下

import logging
import logging.config
import yaml
import a

with open('config.yaml', 'r', encoding='utf-8') as f:
    config = yaml.load(f)
    logging.config.dictConfig(config)

logging.info('main file log')
a.run()

4、with…as…

那么with和as也是一种防止报错的防范方式,
当python执行这一句时,会调用__enter__函数,然后把该函数return的值传给as后指定的变量。
之后,python会执行下面do something的语句块。最后不论在该语句块出现了什么异常,都会在离开时执行__exit__。

ith open("x.txt") as f:
    data = f.read()

with open("x.txt") as f1, open('xxx.txt') as f2:
    do something with f1,f2

那么try和with也可以合起:

try:
    with open( "a.txt" ) as f :
        do something
except xxxError:
    do something about exception

延伸:报错提示如何写ValueError()

if pretrained_model not in self._models:
    raise ValueError(
        'The n_class needs to be supplied as an argument.')

5 主动发出报错raise

参考url:https://blog.csdn.net/skullfang/article/details/78820541

raise RuntimeError('testError')

6 Logger好用的新库:loguru

6.1 文件保存

#!pip install loguru

使用起来:

from loguru import logger
import sys

# 文件保存
# logger.add("log/file.log", rotation="12:00")     # 每天中午12点,自动完成归档,并启用新日志文件
# logger.add('runtime_{time}.log', rotation="500 MB")  # 设置超过 500 MB 新创建一个 log 文件
# logger.add('runtime_{time}.log', rotation='1 week') # 设置每隔一个周新创建一个 log 文件
# logger.add('runtime_{time}.log', compression='zip')  # 可以配置日志文件的压缩格式,这样可以更加节省存储空间,比如设置使用 zip 文件格式保存
logger.add('log/runtime_{time}.log', rotation='00:00') # 每天0点,自动完成归档,并启用新日志文件
logger.add(sys.stdout, colorize=True)     # 将日志输出到控制台,并添加颜色

在这里插入图片描述

6.2 文件保存与删除


# 文件保存与删除
logger.remove(log_file) # 删除
logger.add('runtime_{time}.log', retention='15 days') # 可以设置日志的最长保留时间,比如设置日志文件最长保留 15 天
logger.add('runtime_{time}.log', retention=10)  # 设置日志文件最多保留 10 个

# 文件定时删除
    # 也可以是一个 datetime.timedelta 对象,比如设置日志文件最多保留 5 个小时
import datetime
from loguru import logger
logger.add('runtime_{time}.log', retention=datetime.timedelta(hours=5))



6.3 常规用法 + 异常函数追踪 - 非常给力!!



#  常规用法
logger.info("This is log info!")
logger.warning("This is log warn!")
logger.error("This is log error!")
logger.debug("This is log debug!")

# 异常函数追踪 - 非常给力!!
from loguru import logger
@logger.catch
def my_function(x, y, z):
    # An error? It's caught anyway!
    return 1 / (x + y + z)

my_function(0, 0, 0)


参考文献:

Loguru:Python 日志终极解决方案
loguru:python开箱即用的日志库

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/493189.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Java 并发编程】一文详解 Java 内置锁 synchronized

一文详解 Java 内置锁 synchronized 1. 前言1.1 并发编程中存在线程安全问题1.2 设计同步器的意义1.3 如何解决线程并发安全问题&#xff1f; 2. synchronized 的用法2.1 修饰实例方法&#xff0c;锁是当前实例对象2.2 修饰静态方法&#xff0c;锁是当前类对象2.3 修饰代码块&a…

简单创建SSM项目

1、在idea中创建项目 点击new-project&#xff0c;点击Maven项目&#xff0c;勾选 creat from archetype &#xff0c;找到maven-archetype-webapp 写好相关信息 点击下一步&#xff0c;需要检查maven环境 点击后下载对应的插件&#xff0c;选择项目地址。 开始下载资源&#x…

rust vscode编辑器常用插件与配置

插件&#xff1a;rust-analyzer 会实时编译和分析你的 Rust 代码&#xff0c;提示代码中的错误&#xff0c;并对类型进行标注 插件的完整手册地址&#xff1a;https://rust-analyzer.github.io/manual.html。 插件&#xff1a; rust syntax 为代码提供语法高亮。 …

就挺无语的,这是有脾气的博客

文章目录 前言1. 背景2. 使用3. 公众号体验4. 结束语 前言 ChatGPT已经推出两个多月了&#xff0c;热度已经不减。ChatGPT由人工智能研究实验室OpenAI在2022年11月30日发布的全新聊天机器人模型&#xff0c;一款人工智能技术驱动的自然语言处理工具。它能够通过学习和理解人类的…

大厂都用DevOps!十分钟带你了解自动化在DevOps中的运用

Hi&#xff0c;大家好。DevOps、CI/CD、Docker、Kubernetes……好像全世界都在谈论这些技术&#xff0c;以至于你觉得即将到达NoOps阶段。别担心&#xff0c;在工具和各种最佳实践的浩瀚海洋中感到迷失是正常的&#xff0c;是时候让我们来分析一下DevOps到底是什么了。 一、De…

JAVA类加载机制

在Java的世界里&#xff0c;每一个类或者接口&#xff0c;在经历编译器后&#xff0c;都会生成一个个.class文件。 类加载机制指的是将这些.class文件中的二进制数据读入到内存中&#xff0c;并对数据进行校验&#xff0c;解析和初始化。最终&#xff0c;每一个类都会在方法区保…

ChatGPT - 学习和提高新技能的Prompt

文章目录 Prompt例子 Prompt “我想学习/提高[技能]。我是一个完全的初学者。创建一个30天的学习计划&#xff0c;可以帮助像我这样的初学者学习和提高这项技能。”例子 我想学习/提高Flink。我是一个完全的初学者。 创建一个30天的学习计划&#xff0c;可以帮助像我这样的初…

Xilinx Artix-7【XC7A35T-2CSG324I】【XC7A35T-1CSG324I】成本与收发器优化的FPGA器件

产品介绍&#xff1a; Xilinx Artix -7系列 FPGA 重新定义了成本敏感型解决方案&#xff0c;功耗比上一代产品降低了一半&#xff0c;同时为高带宽应用提供一流的收发器和信号处理能力。这些设备基于 28 纳米 HPL 工艺构建&#xff0c;提供一流的性能功耗比。与 MicroBlaze™ 软…

boot-admin整合Liquibase实现数据库版本管理

Liquibase 和 Flyway 是两款成熟的、优秀的、开源/商业版的数据库版本管理工具&#xff0c;鉴于 Flyway 的社区版本对 Oracle 数据库支持存在限制&#xff0c;所以 boot-admin 选择整合 Liquibase 提供数据库版本管理能力支持。 Liquibase 开源版使用 Apache 2.0 协议。 Liqui…

实现服务器版本---表白墙(Servlet)

目录 一、创建Servlet项目 二、约定前后端交互接口 三、前端代码 四、后端代码 五、效果演示 结合Servlet API &#xff0c;实现一个服务器版本表白墙。实现的这个表白墙&#xff0c;就通过服务器来保存这里的消息数据&#xff0c;进而做到 “持久化” 存储。 一、创建Se…

浮点数中的阶码和尾数

阶码和尾数 阶码尾数浮点数浮点数表示示例 例题分析总结 阶码 在机器中表示一个浮点数时需要给出指数&#xff0c;这个指数用整数形式表示&#xff0c;这个整数叫做阶码。 尾数 常用对数的小数部分&#xff0c;用于科学计数法&#xff0c;其表示方法为:Mantissa x Base^Expo…

k210单片机的串口交互实验

先来看看实验的结果吧&#xff0c;k210的9口为RX&#xff0c;10口为TX。接线&#xff1a; 9口接usb转ttl的TX 10口接usb转ttl的RX 下面介绍一下k210需要使用的模块&#xff1a; K210 一共有 3 个串口&#xff0c;每个串口可以自由映射引脚。 例&#xff1a; # IO10→RX1&#…

JuiceFS__持久化缓存源码走读

JuiceFS__持久化缓存源码走读 JuiceFS 是一款高性能 POSIX 文件系统&#xff0c;针对云原生环境特别优化设计&#xff0c;在 Apache 2.0 开源协议下发布。使用 JuiceFS 存储数据&#xff0c;数据本身会被持久化在对象存储&#xff08;例如 Amazon S3&#xff09;&#xff0c;而…

java小记 2023-05-05

public class Test {/*** 谓类的方法就是指类中用static 修饰的方法&#xff08;非static 为实例方法&#xff09;&#xff0c;比如main 方法&#xff0c;那么可以以main* 方法为例&#xff0c;可直接调用其他类方法&#xff0c;必须通过实例调用实例方法&#xff0c;this 关键…

7.3 有源滤波电路(2)

四、开关电容滤波器 开关电容电路由受时钟脉冲信号控制的模拟开关、电容器和运算放大电路三部分组成。这种电路的特性与电容器的精度无关&#xff0c;而仅与各电容器电容量之比的准确性有关。在集成电路中&#xff0c;可以通过均匀地控制硅片上氧化层的介电常数及其厚度&#…

国产版ChatGPT大盘点

我们看到,最近,国内大厂开始密集发布类ChatGPT产品。 一方面,是因为这是最近10年最大的趋势和机会。 另一方面,国内的AI,不能别国外卡了脖子。 那在类ChatGPT赛道上,哪些中国版的ChatGPT能快速顶上?都各有哪些困境需要突破呢?本文给诸位带来各个玩家的最新进展。 *…

大数据Doris(十二):Unique数据模型

文章目录 Unique数据模型 一、读时合并 二、写时合并 Unique数据模型 在某些多维分析场景下,用户更关注的是如何保证 Key 的唯一性,即如何获得 Primary Key 唯一性约束。因此,我们引入了 Unique 数据模型,该模型可以根据相同的Primary Key 来保留后插入的数据,确保数据…

Day962.如何更好地重构和组织后端代码 -遗留系统现代化实战

如何更好地重构和组织后端代码 Hi&#xff0c;我是阿昌&#xff0c;今天学习记录是关于如何更好地重构和组织后端代码的内容。 如果说在气泡上下文中开发新的需求&#xff0c;类似于老城区旁边建设一个新城区&#xff0c;那么在遗留系统中开发新的需求&#xff0c;就类似于在…

c++的构造函数与析构函数

构造函数是一种特殊的成员函数&#xff0c;用于在对象创建时初始化对象的成员变量。它的名称与类名相同&#xff0c;没有返回类型&#xff0c;可以有参数。当创建对象时&#xff0c;构造函数会自动调用&#xff0c;以初始化对象的成员变量。如果没有定义构造函数&#xff0c;编…

华为OD机试真题-24点运算【2023】【JAVA】

一、题目描述 计算24点是一种扑克牌益智游戏&#xff0c;随机抽出4张扑克牌&#xff0c;通过加()&#xff0c;减(-)&#xff0c;乘(*), 除(/)四种运算法则计算得到整数24&#xff0c;本问题中&#xff0c;扑克牌通过如下字符或者字符串表示&#xff0c;其中&#xff0c;小写jo…