Python 日志-装饰器

2023-11-14

参考文章:程序员小谭-自动化项目实战08:日志

插入脚本展示

在这里插入图片描述

代码实现

def write_case_log():
    def wrapper_func(func):
        @wraps(func) # 防止函数名称与注释文档被重写
        def inner_func(*args,**kwargs):
            try:
                logger1.info("{}开始执行".format(func.__name__))
                func(*args,**kwargs)
                logger1.info("{}执行中".format(func.__name__))
                logger1.info("{}结束执行".format(func.__name__))
            except Exception as msg:
                logger1.error('%s 执行失败' % (func.__name__))
                logger1.error(msg)
                logger1.error(traceback.format_exc())
        return inner_func
    return wrapper_func

实现结果

  • 控制台输出
  • 文件输出
  • 异常写入日志
  • 装饰器调用

在这里插入图片描述

疑问点

为何装饰器输入的时候,需要带入write_case_log(),使用的是函数返回结果,而不是write_case_log函数?
当将括号去掉,会提示:此函数不需要位置参数,但给了一个位置参数。
在这里插入图片描述
其实write_case_log()等同于直接使用warpper_func,此处只是原作者将其多嵌套了一层进行封装。
装饰器的执行,就是将目标函数名带入到装饰器函数中执行。

知识巩固

菜鸟教程-装饰器
1、@wraps(func) 具备复制函数名,注释文档等功能,防止原函数名被重写,可使用print(func_XX.__name__)检查
2、可通过多嵌套一层,实现带参数的装饰器

from functools import wraps
def logit(logfile='out.log'):
    def logging_decorator(func):
        @wraps(func)
        def wrapped_function(*args, **kwargs):
            log_string = func.__name__ + " was called"
            print(log_string)
            # 打开logfile,并写入内容
            with open(logfile, 'a') as opened_file:
                # 现在将日志打到指定的logfile
                opened_file.write(log_string + '\n')
            return func(*args, **kwargs)
        return wrapped_function
    return logging_decorator
@logit(logfile='func2.log')
def myfunc2():
    pass
myfunc2()

3、装饰器类

装饰器类
现在我们有了能用于正式环境的logit装饰器,但当我们的应用的某些部分还比较脆弱时,异常也许是需要更紧急关注的事情。比方说有时你只想打日志到一个文件。而有时你想把引起你注意的问题发送到一个email,同时也保留日志,留个记录。这是一个使用继承的场景,但目前为止我们只看到过用来构建装饰器的函数。
幸运的是,类也可以用来构建装饰器。那我们现在以一个类而不是一个函数的方式,来重新构建logit。

from functools import wraps
class logit(object):
    def __init__(self, logfile='out.log'):
        self.logfile = logfile
 
    def __call__(self, func):
        @wraps(func)
        def wrapped_function(*args, **kwargs):
            log_string = func.__name__ + " was called"
            print(log_string)
            # 打开logfile并写入
            with open(self.logfile, 'a') as opened_file:
                # 现在将日志打到指定的文件
                opened_file.write(log_string + '\n')
            # 现在,发送一个通知
            self.notify()
            return func(*args, **kwargs)
        return wrapped_function
 
    def notify(self):
        # logit只打日志,不做别的
        pass
这个实现有一个附加优势,在于比嵌套函数的方式更加整洁,而且包裹一个函数还是使用跟以前一样的语法:

@logit()
def myfunc1():
    pass
现在,我们给 logit 创建子类,来添加 email 的功能(虽然 email 这个话题不会在这里展开)class email_logit(logit):
    '''
    一个logit的实现版本,可以在函数调用时发送email给管理员
    '''
    def __init__(self, email='admin@myproject.com', *args, **kwargs):
        self.email = email
        super(email_logit, self).__init__(*args, **kwargs)
 
    def notify(self):
        # 发送一封email到self.email
        # 这里就不做实现了
        pass
从现在起,@email_logit 将会和 @logit 产生同样的效果,但是在打日志的基础上,还会多发送一封邮件给管理员。

完整脚本

import logging
from common import configContral
import time
import traceback
from functools import wraps

logConfig = configContral.logConfig
logName_logger = logConfig.logName_configContral
levels_logger = logConfig.levels_configContral
# 第一步,创建一个logger
logger1 = logging.getLogger()
if levels_logger.upper() == "DEBUG":
    logger1.setLevel(logging.DEBUG)
elif levels_logger.upper() == "INFO":
    logger1.setLevel(logging.INFO)
elif levels_logger.upper() == "WARNING":
    logger1.setLevel(logging.WARNING)
elif levels_logger.upper() == "ERROR":
    logger1.setLevel(logging.ERROR)
else:
    logger1.setLevel(logging.CRITICAL)

# 第二步,创建一个handler,用于写入日志文件
now = time.strftime("%Y-%m-%d", time.localtime(time.time()))
# 打开一个文件,将result写入此file中
logfile = logConfig.logPath_configContral + now + logName_logger

fileHandler = logging.FileHandler(logfile, encoding='utf-8')

# 第三步,创建一个handler,用于输出控制台
outputFile_handler = logging.StreamHandler()

# 第四步,定义handler的输出格式
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s %(message)s")
fileHandler.setFormatter(formatter)
outputFile_handler.setFormatter(formatter)

# 第五步,将logger添加到handler里面
logger1.addHandler(fileHandler)
logger1.addHandler(outputFile_handler)


def write_case_log():

    def wrapper_func(func):
        @wraps(func) # 防止函数名称与注释文档被重写
        def inner_func(*args,**kwargs):
            try:
                logger1.info("{}开始执行".format(func.__name__))
                func(*args,**kwargs)
                logger1.info("{}执行中".format(func.__name__))
                logger1.info("{}结束执行".format(func.__name__))
            except Exception as msg:
                logger1.error('%s 执行失败' % (func.__name__))
                logger1.error(msg)
                logger1.error(traceback.format_exc())
        return inner_func
    return wrapper_func

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python 日志-装饰器 的相关文章

随机推荐

  • 【Redis】缓存问题

    用户数据一般都是存储在数据库中 数据库则落在磁盘上 而磁盘的I O速度是计算机中最慢的硬件 当用户的访问量在某一个时间段突然上升 数据库就很容易崩溃 为了避免用户直接访问数据库 所以会使用缓存数据库 Redis 作为缓冲层 Redis 是内
  • mysql topn_TopN语句

    TopN语句常用于计算实时数据中对某个指标的最大或者最小的前N个数据的筛选 Flink SQL可以基于 OVER窗口操作灵活地完成TopN的工作 语法 SELECT FROM SELECT ROW NUMBER OVER PARTITION
  • 基于FPAG高精度频率与电压测量系统

    基于FPAG高精度频率与电压测量系统 1 系统功能与组成 本次设计的是一个测量频率与电压的系统 其中方波频率范围 在5k 50k内可以精确到小数点后两位测量原理为计算待测频率的周期 电压采用12位双路AD 采样频率为50Mhz 测量的值通过
  • 使用 UpdatePanel

    1 概述 ASP NET UpdatePanel 控件能让你创建丰富的 以客户为中心的 Web 应用程序 使用 UpdatePanel 控件 可以刷新选择的页面部分而不是使用回发来刷新整个页面 这就像是执行了一个局部页面更新一样 包含一个
  • 删除指定文件夹内创建时间24小时之外的所有文件

    File dir new File D dir File list dir listFiles for File file list if new Date getTime file lastModified gt 24 60 60 100
  • 2013我国软件业务收入百强企业揭晓 华为夺冠 (zz)

    z 2013 07 10 10 01 59 IS2120 BG57IV3 T4270528460 K T280 L4220 R118 V3466 新华网5月14日消息 2013年 第十二届 软件前百家企业业务收入达3667亿元 华为 海尔
  • redis扣库存-秒杀活动使用

    简单利用redis的LUA脚本功能 一次性操作 实现原子性扣减库存 注释都写得明白 大家凑合着看吧 没有增加库存 直接是初始化一次库存量 后面等过期失效 特别注意一点 就是在集群模式下 需要解决依赖问题 第二个是 序列化的时候 需要把int
  • STM32学习笔记---TFT-LCD

    一 常见显示器介绍 1 显示器分类 显示器属于计算机的 I O 设备 即输入输出设备 它是一种将特定电子信息输出到屏幕上再反射到人眼的显示工具 常见显示器有三类 CRT显示器 LCD液晶显示器 LED点阵显示器 1 1 CRT显示器
  • Golang基础(指针)

    一 变量地址 变量本质就是内存中一块数据的标记 把值存储到变量中实质是把值存储到内存中 每次对变量重新赋值就是在修改变量地址中的内容 在Go语言中可以通过 变量名 获取到变量地址值 重新创建一个非引用型变量 即使是把已有变量直接赋值给新变量
  • Python爬虫实战之电影爬取过程

    俗话说 兴趣所在 方能大展拳脚 so结合兴趣的学习才能事半功倍 更加努力专心 apparently本次任务是在视频网站爬取一些好看的小电影 地址不放 狗头保命 只记录过程 实现功能 从网站上爬取采用m3u8分段方式的视频文件 对加密的 ts
  • 常见的开源协议有哪些

    开源软件 Open source software 的源代码对有追求的程序员来说是一无尽的宝藏 此外正确的使用开源软件 可以提高开发软件时的效率 提升软件质量 但是在使用和借鉴开源软件的时候 我们不得不关心一下它对使用者的诸多限制 比较常见
  • vscode怎么使用live server

    步骤 1 点击左边活动栏最下面的插件按钮 2 在输入框搜索live server插件 大概输完 live 下面就出现了 3 安装live server插件 4 此时右下角状态栏会出现 go live 图解 像这样子 就可以了
  • openstack创建域、项目、用户、角色报错

    报错出现 An unexpected error prevented the server from fulfilling your request HTTP 500 1 创建项目service openstack project crea
  • URL传参

    传递多个参数 URL report asp ID 123 paramterName2 456 kehu Server UrlEncode 客户名 取值 Request paramterName eg Request ID 提交表单的时候 会
  • React扩展知识

    目录 setState lazyLoad Hooks 1 React Hook Hooks是什么 2 三个常用的Hook 3 State Hook 4 Effect Hook Ref Hook 代码示例 Fragment Context 组
  • js对象常用方法

    for in遍历对象 let user name John age 30 isAdmin true for let key in user keys alert key name age isAdmin 属性键的值 alert user k
  • Linux下安装hbase

    系统环境 银河麒麟V10 JDK8 Hbase2 2 7 一 安装JDK 1 下载地址 http www oracle com technetwork java javase downloads jdk8 downloads 2133151
  • css 水平垂直居中的几种常见方式

    下面是几种常见的水平垂直居中方式 可在不同情形下方便采用不同的方式 html div class box div class content div div 共同的css content width 50 height 50 margin
  • C++中的STL中map用法详解

    map用法详解 Map是STL的一个关联容器 它提供一对一的数据处理能力 由于这个特性 它完成有可能在我们处理一对一数据的时候 在编程上提供快速通道 这里说下map内部数据的组织 map内部自建一颗红黑树 一 种非严格意义上的平衡二叉树 这
  • Python 日志-装饰器

    参考文章 程序员小谭 自动化项目实战08 日志 插入脚本展示 代码实现 def write case log def wrapper func func wraps func 防止函数名称与注释文档被重写 def inner func ar