Python 异常处理与日志记录

👽发现宝藏

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。

异常处理是任何编程语言中的重要组成部分,Python 也不例外。Python 提供了丰富的异常处理机制,让开发者可以更好地管理程序中出现的错误。除了捕获和处理异常外,记录异常信息也是至关重要的,以便日后排查问题和改进程序。本文将介绍如何在 Python 中捕获异常,并将异常信息记录到日志文件中。

异常处理

在 Python 中,使用 try-except 语句来捕获异常。try 代码块中放置可能引发异常的代码,except 代码块中处理异常情况。

try:# 可能引发异常的代码result = 10 / 0
except ZeroDivisionError as e:# 处理异常情况print("除零错误发生:", e)

在上面的例子中,当除以零时会触发 ZeroDivisionError 异常,except 代码块会捕获这个异常并进行处理。

异常日志记录

除了简单地在控制台打印异常信息,我们还可以将异常信息记录到日志文件中,以便后续分析。Python 提供了内置的 logging 模块,可以轻松实现这一功能。

import logging# 配置日志记录器
logging.basicConfig(filename='error.log', level=logging.ERROR)try:result = 10 / 0
except ZeroDivisionError as e:# 记录异常信息到日志文件logging.error("除零错误发生: %s", e)

在上述代码中,我们首先通过 basicConfig 方法配置了日志记录器,指定了日志文件名为 error.log,并设置记录级别为 ERROR,这意味着只有 ERROR 级别及以上的日志才会被记录。然后,在 except 代码块中,我们使用 logging.error 方法将异常信息记录到日志文件中。

日志文件分析

通过记录异常信息到日志文件,我们可以随时查看程序运行中出现的异常情况,以便及时定位和解决问题。可以使用文本编辑器或日志分析工具来查看日志文件内容,分析异常发生的原因和频率。

error.log:ERROR:root:除零错误发生: division by zero

上述日志文件记录了一条除零错误的异常信息,其中包含了异常类型和具体错误信息。通过分析日志文件,我们可以清晰地了解到程序中存在的问题,并采取相应的措施进行修复。

高级日志记录配置

除了基本的日志记录配置外,logging 模块还提供了更多高级的配置选项,以满足不同场景下的需求。

1. 添加时间戳

可以通过配置 format 参数来添加时间戳到日志记录中,以便更好地跟踪异常发生的时间。

import logginglogging.basicConfig(filename='error.log', level=logging.ERROR, format='%(asctime)s - %(levelname)s - %(message)s')
2. 指定日志格式

可以通过配置 format 参数来指定日志的格式,以便更清晰地展示异常信息。

import logginglogging.basicConfig(filename='error.log', level=logging.ERROR, format='%(asctime)s - %(levelname)s - %(message)s - %(filename)s:%(lineno)d')
3. 添加异常堆栈信息

可以通过设置 exc_info 参数为 True 来添加异常的堆栈信息到日志记录中。

import loggingtry:result = 10 / 0
except ZeroDivisionError as e:logging.error("除零错误发生: %s", e, exc_info=True)
4. 日志分级

除了 ERROR 级别外,logging 模块还支持其他几种日志级别,包括 DEBUG、INFO、WARNING、CRITICAL 等。可以根据实际需求选择合适的日志级别进行记录。

import logginglogging.basicConfig(filename='app.log', level=logging.DEBUG)

日志轮换与归档

对于大型项目或长期运行的程序,日志文件可能会变得非常庞大。为了解决这个问题,logging 模块支持日志轮换和归档功能,可以按照一定的策略将日志文件分割、压缩或移动到其他位置。

import logging
from logging.handlers import RotatingFileHandlerhandler = RotatingFileHandler('app.log', maxBytes=10000, backupCount=5)
handler.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)logger = logging.getLogger(__name__)
logger.addHandler(handler)logger.debug('This is a debug message')

在上述代码中,我们使用 RotatingFileHandler 类来实现日志轮换功能,设置了日志文件的最大字节数为 10000 字节,备份文件的数量为 5。当日志文件大小超过设定的最大字节数时,会自动创建新的日志文件,并将旧的日志文件备份。

日志配置文件

在较大的项目中,可能需要更加灵活和复杂的日志配置。为了避免在代码中硬编码日志配置,可以将日志配置信息单独存放在一个配置文件中,例如 logging.conf

[loggers]
keys=root[handlers]
keys=fileHandler[formatters]
keys=myFormatter[logger_root]
level=DEBUG
handlers=fileHandler[handler_fileHandler]
class=FileHandler
level=DEBUG
formatter=myFormatter
args=('app.log',)[formatter_myFormatter]
format=%(asctime)s - %(levelname)s - %(message)s

然后在 Python 代码中使用 logging.config 模块加载配置文件。

import logging
import logging.configlogging.config.fileConfig('logging.conf')logger = logging.getLogger(__name__)
logger.debug('This is a debug message')

异常链追踪

有时候,程序中的异常不仅仅是由当前位置的代码引发的,可能还涉及到调用栈上的其他函数或模块。为了更好地追踪异常的来源,可以使用 logging.exception 方法来记录异常链。

import loggingtry:result = 10 / 0
except ZeroDivisionError as e:logging.exception("除零错误发生")

上述代码会将当前异常以及调用栈上的所有异常信息记录到日志中,方便后续排查问题。

异常处理装饰器

为了简化异常处理的代码,可以定义一个异常处理的装饰器,统一处理函数中的异常情况。

import logging
from functools import wrapsdef handle_exceptions(logger):def decorator(func):@wraps(func)def wrapper(*args, **kwargs):try:return func(*args, **kwargs)except Exception as e:logger.exception("异常发生: %s", e)return wrapperreturn decoratorlogger = logging.getLogger(__name__)@handle_exceptions(logger)
def divide(x, y):return x / yresult = divide(10, 0)

上述代码定义了一个名为 handle_exceptions 的装饰器,可以将函数中的异常信息记录到日志中。然后,我们将 divide 函数应用了该装饰器,即使在函数内部发生异常,也会被捕获并记录到日志中。

日志记录的性能考虑

在实际项目中,日志记录的性能也是需要考虑的重要因素。过于频繁或过度详细的日志记录可能会对程序的性能产生负面影响,因此需要在记录足够信息的同时,尽量减少对性能的影响。

1. 日志级别控制

在配置日志记录器时,可以根据不同的场景和需求设置不同的日志级别。在开发和测试阶段,可以设置为 DEBUG 级别以记录更详细的信息,而在生产环境中,可以设置为 WARNING 或更高级别以减少日志记录的数量,从而降低对性能的影响。

import logginglogging.basicConfig(level=logging.DEBUG)  # 开发/测试环境
# logging.basicConfig(level=logging.WARNING)  # 生产环境
2. 异步日志记录

为了减少日志记录对主程序的阻塞,可以使用异步日志记录器,将日志记录操作放到独立的线程或进程中执行,从而提高程序的响应速度。

import logging
import logging.handlerslogger = logging.getLogger(__name__)
handler = logging.handlers.QueueHandler()
logger.addHandler(handler)queue = logging.handlers.QueueListener(handler, *logger.handlers)
queue.start()
3. 批量写入

在高并发环境中,频繁地向日志文件写入可能会导致文件 I/O 压力过大,影响系统性能。为了解决这个问题,可以考虑将日志记录操作改为批量写入,例如使用队列缓存日志消息,然后定期将队列中的消息批量写入日志文件。

import logging
import queue
import threadinglog_queue = queue.Queue()def log_worker():while True:record = log_queue.get()logger = logging.getLogger(record.name)logger.handle(record)log_queue.task_done()thread = threading.Thread(target=log_worker, daemon=True)
thread.start()logging.basicConfig(level=logging.INFO)
logging.handlers.QueueHandler(log_queue)

日志记录的安全性考虑

除了性能和功能需求外,日志记录的安全性也是需要考虑的重要因素。在实际项目中,可能存在一些敏感信息需要记录,如用户密码、API 密钥等,如果不加以保护,可能会造成信息泄露和安全漏洞。

1. 敏感信息过滤

在记录日志时,应当避免将敏感信息直接记录到日志中,尤其是在生产环境中。可以通过过滤器来检查日志消息,将其中的敏感信息进行替换或删除。

import loggingclass SensitiveFilter(logging.Filter):def filter(self, record):record.msg = record.msg.replace('password', '***')return Truelogger = logging.getLogger(__name__)
logger.addFilter(SensitiveFilter())
2. 安全存储

日志文件本身可能包含敏感信息,因此需要采取相应的安全措施来保护日志文件的安全性。可以将日志文件存储在受限制的访问路径下,设置合适的文件权限,以及定期清理和归档日志文件。

import logginglogging.basicConfig(filename='/var/log/app.log', level=logging.INFO)
3. 加密传输

如果日志信息需要通过网络传输,应当采取加密的方式来保护数据的安全性,防止被中间人窃取或篡改。可以使用 TLS/SSL 协议来加密日志传输通道。

import logging
import logging.handlershandler = logging.handlers.SysLogHandler(address=('localhost', 514))
handler.socktype = socket.SOCK_STREAM
handler.ssl_context = ssl.create_default_context()logger = logging.getLogger(__name__)
logger.addHandler(handler)

日志记录审计

除了安全性考虑外,日志记录还可以用于审计目的,帮助监控系统的运行情况、用户行为和操作记录,以及追踪安全事件和异常情况。通过分析日志记录,可以及时发现潜在的安全威胁和漏洞,并采取相应的措施进行预防和应对。

import logginglogging.basicConfig(filename='audit.log', level=logging.INFO)def audit_log(func):def wrapper(*args, **kwargs):result = func(*args, **kwargs)logging.info(f'{func.__name__} called with arguments: {args}, {kwargs}. Result: {result}')return resultreturn wrapper@audit_log
def add(x, y):return x + yadd(3, 4)

在上述代码中,我们定义了一个名为 audit_log 的装饰器,用于记录函数调用的参数和结果到审计日志文件中。通过对关键操作和敏感函数应用该装饰器,可以实现对系统行为的全面监控和审计。

日志监控和警报

除了记录日志和审计功能外,日志监控和警报也是关键的安全实践。通过监控日志文件的变化、异常和异常频率,可以及时发现系统中的异常行为和安全威胁,从而采取相应的措施进行响应和修复。

1. 实时监控

使用监控工具或脚本定期扫描日志文件,监控日志文件的变化和异常情况,及时发现和处理异常事件。

import os
import timelogfile = '/var/log/app.log'def monitor_logfile(logfile):while True:with open(logfile, 'r') as f:f.seek(0, os.SEEK_END)new_data = f.read()if new_data:print("发现新日志:", new_data)time.sleep(10)monitor_logfile(logfile)
2. 异常警报

当发现异常日志时,可以通过发送警报通知管理员或安全团队,以便及时响应和处理。

import smtplib
from email.mime.text import MIMETextdef send_alert(subject, message):sender_email = "your_email@example.com"receiver_email = "admin@example.com"password = "your_email_password"msg = MIMEText(message)msg['Subject'] = subjectmsg['From'] = sender_emailmsg['To'] = receiver_emailserver = smtplib.SMTP('smtp.example.com', 587)server.starttls()server.login(sender_email, password)server.sendmail(sender_email, receiver_email, msg.as_string())server.quit()# 在发现异常时调用 send_alert 函数发送邮件警报
3. 日志分析

使用日志分析工具或脚本对日志文件进行分析,识别异常行为、异常模式和安全事件,以及监控系统运行状态和性能表现。

import redef analyze_logfile(logfile):pattern = r'ERROR|WARNING'with open(logfile, 'r') as f:for line in f:if re.search(pattern, line):print("发现异常日志:", line)analyze_logfile(logfile)

自动化响应

为了进一步提高安全性和响应速度,可以将日志监控和警报的流程自动化,通过脚本或自动化工具来自动检测、警报和响应异常事件。

import subprocessdef automate_response(logfile):pattern = r'ERROR|WARNING'result = subprocess.run(['grep', '-E', pattern, logfile], capture_output=True)if result.stdout:send_alert("发现异常日志", result.stdout.decode())automate_response(logfile)

日志备份和恢复

除了监控和警报外,日志备份和恢复也是关键的安全实践。定期备份日志文件可以防止日志丢失或被篡改,同时在需要时可以快速恢复到历史状态,帮助排查问题和恢复系统功能。

1. 定期备份

使用定时任务或脚本定期备份日志文件,将当前日志文件复制到备份目录或存储介质中,以确保日志数据的安全性和可靠性。

import shutil
import timedef backup_logfile(logfile, backup_dir):timestamp = time.strftime('%Y%m%d%H%M%S')backup_file = f'{backup_dir}/app_{timestamp}.log'shutil.copy(logfile, backup_file)
2. 日志归档

对于长期运行的系统,日志文件可能会变得非常庞大,为了节省存储空间和提高检索效率,可以定期对日志文件进行归档,将旧的日志文件压缩或移动到归档目录中。

import os
import shutil
import zipfiledef archive_logfile(logfile, archive_dir):if os.path.exists(logfile):shutil.move(logfile, archive_dir)with zipfile.ZipFile(f'{archive_dir}/app_logs.zip', 'w') as zipf:zipf.write(f'{archive_dir}/app.log', arcname='app.log')
3. 日志恢复

在需要恢复日志文件时,可以从备份或归档中找到对应的日志文件,并将其复制到原始位置进行恢复。

def restore_logfile(backup_file, original_file):shutil.copy(backup_file, original_file)

日志清理和管理

为了避免日志文件过大或占用过多存储空间,可以定期清理和管理日志文件,删除过期和不必要的日志数据,以保持系统的性能和稳定性。

import os
import globdef cleanup_logs(log_dir, max_age):current_time = time.time()for logfile in glob.glob(f'{log_dir}/*.log'):if os.path.getmtime(logfile) < current_time - max_age:os.remove(logfile)

日志文件加密和权限控制

除了备份和管理外,保护日志文件的安全性也是至关重要的。通过加密日志文件和限制文件权限,可以防止未授权访问和篡改,保障日志数据的保密性和完整性。

1. 文件加密

使用加密算法对日志文件进行加密,以确保日志数据在存储和传输过程中的安全性。可以使用加密库如 cryptography 来实现对日志文件的加密和解密操作。

from cryptography.fernet import Fernetdef encrypt_logfile(logfile, key):with open(logfile, 'rb') as f:data = f.read()fernet = Fernet(key)encrypted_data = fernet.encrypt(data)with open(logfile + '.enc', 'wb') as f:f.write(encrypted_data)def decrypt_logfile(encrypted_file, key):with open(encrypted_file, 'rb') as f:encrypted_data = f.read()fernet = Fernet(key)decrypted_data = fernet.decrypt(encrypted_data)with open(encrypted_file[:-4], 'wb') as f:f.write(decrypted_data)
2. 文件权限控制

通过设置文件权限来限制对日志文件的访问权限,只允许授权用户或组访问和修改日志文件,防止未授权用户篡改或查看日志内容。

import osdef set_file_permissions(logfile, mode):os.chmod(logfile, mode)

日志访问审计

对于敏感信息和重要日志数据,应当实施严格的访问控制和审计机制,记录和监控对日志文件的访问和操作记录,及时发现和处理未授权的访问和异常行为。

import subprocessdef audit_log_access(logfile):result = subprocess.run(['ls', '-l', logfile], capture_output=True)print("日志文件权限信息:", result.stdout.decode())

结论

通过加密日志文件、限制文件权限和实施访问审计,可以有效保护日志数据的安全性和完整性,防止未授权访问和篡改,保障系统的安全运行和数据保护。

在实际项目中,建议结合加密库、操作系统权限控制和审计工具,建立完善的日志安全管理机制,以确保日志系统的安全性和可靠性。

希望本文的介绍能够帮助您更好地理解和应用日志文件加密和权限控制在实际项目中的重要性和作用。

在这里插入图片描述

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

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

相关文章

活动报名 | 如何进行全增量一体的异构数据库实时同步

伴随着新技术的不断涌现&#xff0c;市场竞争也在不断开辟新的角斗场——新的业务需求&#xff0c;新的应用设想都在这里迸发。 面对如此日新月异的竞争环境&#xff0c;企业的当务之急&#xff0c;是为新应用扎根准备好随时可取、准确一致的高质量数据土壤。在这样的背景下&a…

大模型预训练Pretrain

选基座 —> 扩词表 —> 采样&切分数据 —> 设置学习参数 —> 训练 —> 能力测评&#xff09; 基座google/flan-t5 T5 模型&#xff1a;NLP Text-to-Text 预训练模型超大规模探索 - 知乎相信大多 NLP 相关者&#xff0c;在时隔 BERT 发布近一年的现在&…

文件上传复习(upload-labs 6-13关)

Pass-06&#xff08;大小写绕过&#xff09; $is_upload false; $msg null; if (isset($_POST[submit])) {if (file_exists(UPLOAD_PATH)) {$deny_ext array(".php",".php5",".php4",".php3",".php2",".html"…

ardupilot开发 --- Jetson Orin Nano 篇

多情应笑我早生华发 0. 一些概念1. 系统安装&#xff08;刷机、flash&#xff09;1.1 使用SD卡安装系统1.2 使用固态硬盘安装系统 0. 一些概念 官网&#xff1a;https://www.nvidia.com/en-us/DevelopersDocumentationGetting StartedUser Guide论坛 Ask questions or share a…

尚硅谷-JavaSE阶段考试与面试题库

一、基础题 1&#xff09;用最有效的的方法算出2称以8等于几 答案&#xff1a;2<<3 2&#xff09;两个对象a和b&#xff0c;请问ab和a.equals(b)有什么区别&#xff1f; ab&#xff1a;比较对象地址 a.equals(b)&#xff1a;如果a对象没有重写过equals方法&#xff0c…

XiaodiSec day017 Learn Note 小迪安全学习笔记

XiaodiSec day017 Learn Note 小迪安全学习笔记 记录得比较凌乱&#xff0c;不尽详细 day 17 主要内容&#xff1a; php 框架 thinkPHPyiilaravel 使用 fofa 搜索 thinkphp 市面上 thinkphp5 版本较多 url 结构 域名/.php(文件名)/index(目录)/index(函数名)模块名-控…

MySQL、Oracle查看最大连接数和当前连接数

文章目录 1. MySQL2. Oracle 1. MySQL -- 查看最大连接数 show variables like max_connections; select max_connections; -- select * from performance_schema.session_variables where VARIABLE_NAME in (max_connections); -- select * from performance_schema.global…

STL-vector的使用及其模拟实现

在C中&#xff0c;vector是标准模板库&#xff08;STL&#xff09;中的一种动态数组容器&#xff0c;它可以存储任意类型的元素&#xff0c;并且能够自动调整大小。vector提供了许多方便的成员函数&#xff0c;使得对数组的操作更加简单和高效。 vector的使用 vector的构造函数…

YASKAWA安川机器人DX100轴板维修故障细节分享

随着科技的日新月异&#xff0c;机器人在工业生产中扮演的角色愈发重要。而作为机器人的“大脑”——电路板&#xff0c;其稳定运作对整个系统的可靠性至关重要。面对可能出现的YASKAWA安川机器人DX100轴板故障&#xff0c;如何快速、准确地诊断问题并予以解决呢&#xff1f;下…

nginx 卸载和安装超详细教程

一、前言 由于现在nginx有版本漏洞&#xff0c;所以很多安装过nginx的需要卸载重新安装&#xff0c;没安装过的&#xff0c;切记不要乱安装版本。 OK以上版本切记不能再用了&#xff01; 废话不多说&#xff0c;直接上干货。 二、卸载 1、停止Nginx进程 命令行停止&#xf…

《架构风清扬-Java面试系列第26讲》聊聊的LinkedBlockingQueue的特点及使用场景

LinkedBlockingQueue也是BlockingQueue接口的一个实现类之一 这个属于基础性问题&#xff0c;老规矩&#xff0c;我们将从使用场景和代码示例来进行讲解 来&#xff0c;思考片刻&#xff0c;给出你的答案 1&#xff0c;使用场景 实现&#xff1a;基于链表实现的阻塞队列&#…

路由器本地docker 下载node容器部署 thressjs文档

1. 每次启动本地文档太麻烦 &#xff0c;路由器刚好支持docker&#xff08;tp-link6088&#xff09; &#xff0c;部署上去自启动 2.

漫谈AI 时代的信息模型

模型化- 数字化转型的重要基石 在各行各业推行数字化转型过程中&#xff0c;构建信息化模型十分重要&#xff0c;它是数字化转型的基石。事实上&#xff0c;数字化转型的核心是“万物皆模型”&#xff0c;在工业领域&#xff0c;以德国为主导的工业4.0 发展进程中&#xff0c;…

七分钟“手撕”三大特性<多态>

目录 一、学习多态之前需要的知识储备 二、重写 1.什么是重写 2.重写可以干嘛 3.怎么书写重写 4.重载与重写的区别 三、向上转型 1.什么是向上转型&#xff1f; 2.向上转型的语法 3.向上转型的使用场景 四、多态是什么 六、多态实现 七、多态的好处 八、多态的缺…

机器学习/算法工程师面试题目与答案-数学基础部分

机器学习/算法工程师面试题目--数学基础部分 一、数学基础1、微积分SGD,Momentum,Adagard,Adam原理L1不可导的时候该怎么办sigmoid函数特性 2、统计学&#xff0c;概率论求 Max(a, b) 期望拿更长的玫瑰花的最好策略最大化工作天数的员工数切比雪夫不等式随机截成三段组成三角形…

[tkinter实现]汉字笔顺小软件

软件简介 本软件旨在帮助小学生通过互动式学习掌握汉字的基本笔画和笔顺。软件采用Tkinter库构建&#xff0c;提供了一个用户友好的图形界面&#xff0c;适合小学生使用。 主要功能&#xff1a; 汉字展示&#xff1a;软件能够展示单个汉字&#xff0c;并以动画形式演示其标准…

SWOT分析法:知彼知己的战略规划工具

文章目录 一、什么是SWOT分析法二、SWOT分析法如何产生的三、SWOT分析法适合哪些人四、SWOT分析法的应用场景五、SWOT分析法的优缺点六、SWOT分析实例 一、什么是SWOT分析法 SWOT分析法是一种用于评估组织、项目、个人或任何其他事物的战略规划工具。SWOT是Strengths&#xff…

每日OJ题_BFS解决拓扑排序③_力扣LCR 114. 火星词典

目录 力扣LCR 114. 火星词典 解析代码 力扣LCR 114. 火星词典 LCR 114. 火星词典 难度 困难 现有一种使用英语字母的外星文语言&#xff0c;这门语言的字母顺序与英语顺序不同。 给定一个字符串列表 words &#xff0c;作为这门语言的词典&#xff0c;words 中的字符串已…

光伏储能控制系统的功能策略

一、控制策略 1、功率控制策略 光伏阵列的输出功率受光照和温度影响&#xff0c;最大功率点是转换太阳能为电能的最高效点。MPPT控制器根据实时参数调整光伏阵列工作点&#xff0c;确保其始终处于最大功率输出状态&#xff0c;提高能量转换效率&#xff0c;增加发电量&#x…

基于51单片机智能鱼缸仿真LCD1602显示( proteus仿真+程序+设计报告+讲解视频)

基于51单片机智能鱼缸仿真LCD显示 1. 主要功能&#xff1a;2. 讲解视频&#xff1a;3. 仿真4. 程序代码5. 设计报告6. 设计资料内容清单&&下载链接资料下载链接&#xff1a; 基于51单片机智能鱼缸仿真LCD显示( proteus仿真程序设计报告讲解视频&#xff09; 仿真图prot…