iis服务器助手广告
返回顶部
首页 > 资讯 > 服务器 >Python怎么异步发送日志到远程服务器
  • 896
分享到

Python怎么异步发送日志到远程服务器

2023-07-02 15:07:41 896人浏览 八月长安
摘要

本文小编为大家详细介绍“python怎么异步发送日志到远程服务器”,内容详细,步骤清晰,细节处理妥当,希望这篇“Python怎么异步发送日志到远程服务器”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。StreamH

本文小编为大家详细介绍“python怎么异步发送日志到远程服务器”,内容详细,步骤清晰,细节处理妥当,希望这篇“Python怎么异步发送日志到远程服务器”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。

StreamHandler和FileHandler

首先我们先来写一套简单输出到cmd和文件中的代码:

# -*- coding: utf-8 -*-"""------------------------------------------------- File Name:   loger Description : Author :    yangyanxing date:     2020/9/23-------------------------------------------------"""import loggingimport sysimport os# 初始化loggerlogger = logging.getLogger("yyx")logger.setLevel(logging.DEBUG)# 设置日志格式fmt = logging.FORMatter('[%(asctime)s] [%(levelname)s] %(message)s', '%Y-%m-%d%H:%M:%S')# 添加cmd handlercmd_handler = logging.StreamHandler(sys.stdout)cmd_handler.setLevel(logging.DEBUG)cmd_handler.setFormatter(fmt)# 添加文件的handlerlogpath = os.path.join(os.getcwd(), 'debug.log')file_handler = logging.FileHandler(logpath)file_handler.setLevel(logging.DEBUG)file_handler.setFormatter(fmt)# 将cmd和file handler添加到logger中logger.addHandler(cmd_handler)logger.addHandler(file_handler)logger.debug("今天天气不错")

先初始化一个logger, 并且设置它的日志级别是DEBUG,然后添初始化了 cmd_handler和 file_handler,最后将它们添加到logger中, 运行脚本,会在cmd中打印出

[2020-09-23 10:45:56] [DEBUG] 今天天气不错且会写入到当前目录下的debug.log文件中

添加HttpHandler

如果想要在记录时将日志发送到远程服务器上,可以添加一个 HTTPHandler , 在python标准库logging.handler中,已经为我们定义好了很多handler,有些我们可以直接用,本地使用tornado写一个接收 日志的接口,将接收到的参数全都打印出来

# 添加一个httphandlerimport logging.handlershttp_handler = logging.handlers.HTTPHandler(r"127.0.0.1:1987", '/api/log/get')http_handler.setLevel(logging.DEBUG)http_handler.setFormatter(fmt)logger.addHandler(http_handler)logger.debug("今天天气不错")结果在服务端我们收到了很多信息{'name': [b 'yyx'],'msg': [b'\xe4\xbb\x8a\xe5\xa4\xa9\xe5\xa4\xa9\xe6\xb0\x94\xe4\xb8\x8d\xe9\x94\x99'],'args': [b '()'],'levelname': [b 'DEBUG'],'levelno': [b '10'],'pathname': [b 'I:/workplace/yangyanxing/test/loger.py'],'filename': [b 'loger.py'],'module': [b 'loger'],'exc_info': [b 'None'],'exc_text': [b 'None'],'stack_info': [b 'None'],'lineno': [b '41'],'funcName': [b '<module>'],'created': [b '1600831054.8881223'],'msecs': [b '888.1223201751709'],'relativeCreated': [b '22.99976348876953'],'thread': [b '14876'],'threadName': [b 'MainThread'],'processName': [b 'MainProcess'],'process': [b '8648'],'message': [b'\xe4\xbb\x8a\xe5\xa4\xa9\xe5\xa4\xa9\xe6\xb0\x94\xe4\xb8\x8d\xe9\x94\x99'],'asctime': [b '2020-09-23 11:17:34']}

可以说是信息非常之多,但是却并不是我们想要的样子,我们只是想要类似于

[2020-09-23 10:45:56][DEBUG] 今天天气不错这样的日志
logging.handlers.HTTPHandler 只是简单的将日志所有信息发送给服务端,至于服务端要怎么组织内 容是由服务端来完成. 所以我们可以有两种方法,一种是改服务端代码,根据传过来的日志信息重新组织一 下日志内容, 第二种是我们重新写一个类,让它在发送的时候将重新格式化日志内容发送到服务端。

我们采用第二种方法,因为这种方法比较灵活, 服务端只是用于记录,发送什么内容应该是由客户端来决定。

我们需要重新定义一个类,我们可以参考 logging.handlers.HTTPHandler 这个类,重新写一个httpHandler类

每个日志类都需要重写emit方法,记录日志时真正要执行是也就是这个emit方法:

class CustomHandler(logging.Handler):  def __init__(self, host, uri, method="POST"):    logging.Handler.__init__(self)    self.url = "%s/%s" % (host, uri)    method = method.upper()    if method not in ["GET", "POST"]:      raise ValueError("method must be GET or POST")    self.method = method  def emit(self, record):    '''   重写emit方法,这里主要是为了把初始化时的baseParam添加进来   :param record:   :return:   '''    msg = self.format(record)    if self.method == "GET":      if (self.url.find("?") >= 0):        sep = '&'      else:        sep = '?'      url = self.url + "%c%s" % (sep, urllib.parse.urlencode({"log":msg}))      requests.get(url, timeout=1)    else:      headers = {        "Content-type": "application/x-www-form-urlencoded",        "Content-length": str(len(msg))     }      requests.post(self.url, data={'log': msg}, headers=headers,timeout=1)

上面代码中有一行定义发送的参数 msg = self.format(record)这行代码表示,将会根据日志对象设置的格式返回对应的内容。

之后再将内容通过requests库进行发送,无论使用get 还是post方式,服务端都可以正常的接收到日志

{'log': [b'[2020-09-23 11:39:45] [DEBUG]\xe4\xbb\x8a\xe5\xa4\xa9\xe5\xa4\xa9\xe6\xb0\x94\xe4\xb8\x8d\xe9\x94\x99']}

将bytes类型转一下就得到了:

[2020-09-23 11:43:50] [DEBUG] 今天天气不错

异步的发送远程日志

现在我们考虑一个问题,当日志发送到远程服务器过程中,如果远程服务器处理的很慢,会耗费一定的时间, 那么这时记录日志就会都变慢修改服务器日志处理类,让其停顿5秒钟,模拟长时间的处理流程

async def post(self):  print(self.getParam('log'))  await asyncio.sleep(5)  self.write({"msg": 'ok'})

此时我们再打印上面的日志:

logger.debug("今天天气不错")logger.debug("是风和日丽的")

得到的输出为:

[2020-09-23 11:47:33] [DEBUG] 今天天气不错
[2020-09-23 11:47:38] [DEBUG] 是风和日丽的

我们注意到,它们的时间间隔也是5秒。
那么现在问题来了,原本只是一个记录日志,现在却成了拖累整个脚本的累赘,所以我们需要异步的来 处理远程写日志。

1使用多线程处理

首先想的是应该是用多线程来执行发送日志方法;

def emit(self, record):  msg = self.format(record)  if self.method == "GET":    if (self.url.find("?") >= 0):      sep = '&'    else:      sep = '?'    url = self.url + "%c%s" % (sep, urllib.parse.urlencode({"log": msg}))    t = threading.Thread(target=requests.get, args=(url,))    t.start()  else:    headers = {      "Content-type": "application/x-www-form-urlencoded",      "Content-length": str(len(msg))   }    t = threading.Thread(target=requests.post, args=(self.url,), kwargs={"data":{'log': msg},

这种方法是可以达到不阻塞主目的,但是每打印一条日志就需要开启一个线程,也是挺浪费资源的。我们也 可以使用线程池来处理

2使用线程池处理

python 的 concurrent.futures 中有ThreadPoolExecutor, ProcessPoolExecutor类,是线程池和进程池, 就是在初始化的时候先定义几个线程,之后让这些线程来处理相应的函数,这样不用每次都需要新创建线程

线程池的基本使用:

exector = ThreadPoolExecutor(max_workers=1) # 初始化一个线程池,只有一个线程exector.submit(fn, args, kwargs) # 将函数submit到线程池中

如果线程池中有n个线程,当提交的task数量大于n时,则多余的task将放到队列中。
再次修改上面的emit函数

exector = ThreadPoolExecutor(max_workers=1)def emit(self, record):  msg = self.format(record)  timeout = aiohttp.ClientTimeout(total=6)  if self.method == "GET":    if (self.url.find("?") >= 0):      sep = '&'    else:      sep = '?'    url = self.url + "%c%s" % (sep, urllib.parse.urlencode({"log": msg}))    exector.submit(requests.get, url, timeout=6)  else:    headers = {      "Content-type": "application/x-www-form-urlencoded",      "Content-length": str(len(msg))   }    exector.submit(requests.post, self.url, data={'log': msg},headers=headers, timeout=6)

这里为什么要只初始化一个只有一个线程的线程池? 因为这样的话可以保证先进队列里的日志会先被发 送,如果池子中有多个线程,则不一定保证顺序了。

3使用异步aiohttp库来发送请求

上面的CustomHandler类中的emit方法使用的是requests.post来发送日志,这个requests本身是阻塞运 行的,也正上由于它的存在,才使得脚本卡了很长时间,所们我们可以将阻塞运行的requests库替换为异步 的aiohttp来执行get和post方法, 重写一个CustomHandler中的emit方法

class CustomHandler(logging.Handler):  def __init__(self, host, uri, method="POST"):    logging.Handler.__init__(self)    self.url = "%s/%s" % (host, uri)    method = method.upper()    if method not in ["GET", "POST"]:      raise ValueError("method must be GET or POST")    self.method = method  async def emit(self, record):    msg = self.format(record)    timeout = aiohttp.ClientTimeout(total=6)    if self.method == "GET":      if (self.url.find("?") >= 0):        sep = '&'      else:        sep = '?'      url = self.url + "%c%s" % (sep, urllib.parse.urlencode({"log":msg}))      async with aiohttp.ClientSession(timeout=timeout) as session:      async with session.get(self.url) as resp:          print(await resp.text())      else:        headers = {        "Content-type": "application/x-www-form-urlencoded",        "Content-length": str(len(msg))     }      async with aiohttp.ClientSession(timeout=timeout, headers=headers)as session:      async with session.post(self.url, data={'log': msg}) as resp:          print(await resp.text())

这时代码执行崩溃了:

C:\python37\lib\logging\__init__.py:894: RuntimeWarning: coroutine'CustomHandler.emit' was never awaitedself.emit(record)RuntimeWarning: Enable tracemalloc to get the object allocation traceback

服务端也没有收到发送日志的请求。
究其原因是由于emit方法中使用 async with session.post 函数,它需要在一个使用async 修饰的函数 里执行,所以修改emit函数,使用async来修饰,这里emit函数变成了异步的函数, 返回的是一个 coroutine 对象,要想执行coroutine对象,需要使用await, 但是脚本里却没有在哪里调用 await emit() ,所以崩溃信息 中显示 coroutine 'CustomHandler.emit' was never awaited。

既然emit方法返回的是一个coroutine对象,那么我们将它放一个loop中执行

async def main():  await logger.debug("今天天气不错")  await logger.debug("是风和日丽的")loop = asyncio.get_event_loop()loop.run_until_complete(main())

执行依然报错:

raise TypeError('An asyncio.Future, a coroutine or an awaitable is '

意思是需要的是一个coroutine,但是传进来的对象不是。
这似乎就没有办法了,想要使用异步库来发送,但是却没有可以调用await的地方。

解决办法是有的,我们使用 asyncio.get_event_loop() 获取一个事件循环对象, 我们可以在这个对象上注册很多协程对象,这样当执行事件循环的时候,就是去执行注册在该事件循环上的协程,

我们通过一个小例子来看一下:

import asyncioasync def test(n): while n > 0:   await asyncio.sleep(1)   print("test {}".format(n))   n -= 1 return nasync def test2(n): while n >0:   await asyncio.sleep(1)   print("test2 {}".format(n))   n -= 1def stoploop(task): print("执行结束, task n is {}".format(task.result())) loop.stop()loop = asyncio.get_event_loop()task = loop.create_task(test(5))task2 = loop.create_task(test2(3))task.add_done_callback(stoploop)task2 = loop.create_task(test2(3))loop.run_forever()

我们使用 loop = asyncio.get_event_loop() 创建了一个事件循环对象loop, 并且在loop上创建了两个task, 并且给task1添加了一个回调函数,在task1它执行结束以后,将loop停掉。
注意看上面的代码,我们并没有在某处使用await来执行协程,而是通过将协程注册到某个事件循环对象上, 然后调用该循环的 run_forever() 函数,从而使该循环上的协程对象得以正常的执行。

上面得到的输出为:

test 5
test2 3
test 4
test2 2
test 3
test2 1
test 2
test 1
执行结束, task n is 0

可以看到,使用事件循环对象创建的task,在该循环执行run_forever() 以后就可以执行了如果不执行 loop.run_forever() 函数,则注册在它上面的协程也不会执行

loop = asyncio.get_event_loop()task = loop.create_task(test(5))task.add_done_callback(stoploop)task2 = loop.create_task(test2(3))time.sleep(5)# loop.run_forever()

上面的代码将loop.run_forever() 注释掉,换成time.sleep(5) 停5秒, 这时脚本不会有任何输出,在停了5秒 以后就中止了,
回到之前的日志发送远程服务器的代码,我们可以使用aiohttp封装一个发送数据的函数, 然后在emit中将 这个函数注册到全局的事件循环对象loop中,最后再执行loop.run_forever()

loop = asyncio.get_event_loop()class CustomHandler(logging.Handler):  def __init__(self, host, uri, method="POST"):    logging.Handler.__init__(self)    self.url = "%s/%s" % (host, uri)    method = method.upper()    if method not in ["GET", "POST"]:      raise ValueError("method must be GET or POST")    self.method = method  # 使用aiohttp封装发送数据函数  async def submit(self, data):    timeout = aiohttp.ClientTimeout(total=6)    if self.method == "GET":      if self.url.find("?") >= 0:        sep = '&'      else:        sep = '?'      url = self.url + "%c%s" % (sep, urllib.parse.urlencode({"log":data}))      async with aiohttp.ClientSession(timeout=timeout) as session:        async with session.get(url) as resp:          print(await resp.text())    else:      headers = {        "Content-type": "application/x-www-form-urlencoded",     }      async with aiohttp.ClientSession(timeout=timeout, headers=headers)as session:        async with session.post(self.url, data={'log': data}) as resp:          print(await resp.text())    return True  def emit(self, record):    msg = self.format(record)    loop.create_task(self.submit(msg))# 添加一个httphandlerhttp_handler = CustomHandler(r"http://127.0.0.1:1987", 'api/log/get')http_handler.setLevel(logging.DEBUG)http_handler.setFormatter(fmt)logger.addHandler(http_handler)logger.debug("今天天气不错")logger.debug("是风和日丽的")loop.run_forever()

这时脚本就可以正常的异步执行了:

loop.create_task(self.submit(msg)) 也可以使用
asyncio.ensure_future(self.submit(msg), loop=loop) 来代替,目的都是将协程对象注册到事件循环中。

但这种方式有一点要注意,loop.run_forever() 将会一直阻塞,所以需要有个地方调用 loop.stop() 方法. 可以注册到某个task的回调中。

读到这里,这篇“Python怎么异步发送日志到远程服务器”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注编程网服务器频道。

--结束END--

本文标题: Python怎么异步发送日志到远程服务器

本文链接: https://www.lsjlt.com/news/342768.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Python怎么异步发送日志到远程服务器
    本文小编为大家详细介绍“Python怎么异步发送日志到远程服务器”,内容详细,步骤清晰,细节处理妥当,希望这篇“Python怎么异步发送日志到远程服务器”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。StreamH...
    99+
    2023-07-02
  • Python异步发送日志到远程服务器详情
    目录背景StreamHandler和FileHandler添加HTTPHandler1使用多线程处理2使用线程池处理3使用异步aiohttp库来发送请求背景 在Python中使用日志...
    99+
    2024-04-02
  • linux怎么发送日志到服务器
    要发送日志到服务器,可以使用以下方法: 使用rsyslog:rsyslog是一个系统日志守护进程,可以将日志信息发送到远程服务器...
    99+
    2024-04-09
    linux 服务器
  • Golang怎么监听日志文件并发送到kafka中
    这篇文章主要讲解了“Golang怎么监听日志文件并发送到kafka中”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Golang怎么监听日志文件并发送到kafka中”吧!涉及的golang库和...
    99+
    2023-06-30
  • Linux中如何将执行过的命令记录到日志并发送到服务器
    这篇文章主要介绍“Linux中如何将执行过的命令记录到日志并发送到服务器”,在日常操作中,相信很多人在Linux中如何将执行过的命令记录到日志并发送到服务器问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Lin...
    99+
    2023-06-12
  • java怎么发送文件到服务器
    要发送文件到服务器,你可以使用Java的Socket编程来实现。下面是一个示例代码,演示了如何使用Java的Socket编程发送文件到服务器:```javaimport java.io.BufferedInputStream;impor...
    99+
    2023-08-11
    java 服务器
  • Mysql怎么远程备份binlog日志到本地
    本篇内容主要讲解“Mysql怎么远程备份binlog日志到本地”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Mysql怎么远程备份binlog日志到本地”吧! ...
    99+
    2024-04-02
  • 学习 Python 异步编程时,如何将日志记录集成到笔记中?
    Python 是一种非常流行的编程语言,因为它易于学习、易于阅读,并且可以用于多种用途。异步编程是 Python 中的一个重要概念,它可以让你的代码更加高效和响应迅速。在学习 Python 异步编程的过程中,日志记录也是非常重要的一部分。本...
    99+
    2023-11-07
    学习笔记 异步编程 日志
  • 阿里云服务器日志怎么看不到
    下面是一篇简短的800字文章,来介绍如何在阿里云服务器上查看和分析日志。 首先,你需要安装一个Python日志框架,例如logging。 然后,你可以通过命令行或者python客户端查看日志。下面是一个简单的示例: ```python...
    99+
    2023-10-28
    阿里 服务器 日志
  • 阿里云服务器日志怎么看的到
    一、查看硬件信息 首先,我们需要打开阿里云服务器的控制台。进入服务器的主页面,在“系统设置”中找到“系统信息”,然后点击进入“系统信息”页面。在“系统信息”页面中,我们可以看到服务器的硬件信息,包括CPU、内存、磁盘等信息。如果你想查看服...
    99+
    2023-10-28
    阿里 怎么看 服务器
  • 怎么发送数据文档到云服务器
    要将数据文档发送到云服务器,您可以按照以下步骤进行操作:1. 将数据文档上传到云服务器:您可以使用文件传输协议(FTP)或者SCP(...
    99+
    2023-08-12
    云服务器
  • 腾讯云服务器操作日志怎么看不到
    1. 确认权限 首先,您需要确保您拥有足够的权限来查看腾讯云服务器的操作日志。请确保您具有足够的权限,例如管理员或具有日志查看权限的角色。 2. 登录腾讯云控制台 使用您的腾讯云账号登录腾讯云控制台。在控制台的左侧导航栏中,找到并点击 "...
    99+
    2023-10-27
    腾讯 操作 服务器
  • 打包docker镜像推送到远程服务器并部署到k8s的方法步骤
    目录1、Dockerfile2、pom配置3、镜像推送4、k8s部署前提条件: 1、docker服务器已开启远程访问,参考《远程docker服务器携带证书连接》。 2、服务器上已经搭...
    99+
    2024-04-02
  • 阿里云服务器日志怎么看不到内容
    查看日志文件:首先,我们需要打开阿里云服务器的日志文件,例如使用python脚本的openssllogs函数。可以在命令行中输入“ssllogs”,并按回车键执行该脚本。 使用命令查看日志文件:接下来,我们可以使用“findalllogs...
    99+
    2023-10-27
    阿里 服务器 内容
  • 怎么从远程Linux机器上收集日志
    本篇内容主要讲解“怎么从远程Linux机器上收集日志”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么从远程Linux机器上收集日志”吧!如果你的数据中心全是 Linux  服务器,而...
    99+
    2023-06-16
  • PHP发送阿里云邮件服务器异常怎么办
    简介 在使用PHP发送邮件时,有时会遇到阿里云邮件服务器异常的情况。本文将介绍一些常见的问题和解决方法,帮助您解决PHP发送阿里云邮件服务器异常的问题。解决方法1. 检查SMTP配置首先,您需要检查您的PHP代码中的SMTP配置是否正确。确...
    99+
    2024-01-30
    阿里 邮件服务器 异常
  • 服务器日志解密:发现异常活动和安全漏洞
    了解服务器日志 服务器日志是记录服务器活动和事件的文本文件。它们包含有关传入请求、系统错误、安全事件和其他操作的详细信息。常见的服务器日志文件类型包括 Apache 访问日志和 Nginx 错误日志。 解读服务器日志 服务器日志的每一行...
    99+
    2024-03-02
    服务器日志、日志分析、安全漏洞、入侵检测、异常活动监控
  • 【服务器】搭建hMailServer 服务实现远程发送邮件
    typora-copy-images-to: upload hMailServer 是一个邮件服务器,通过它我们可以搭建自己的邮件服务,通过cpolar内网映射工具即可实现远程发送邮件,不需要使用公...
    99+
    2023-10-26
    服务器 java 运维 http
  • 向腾讯云服务器发送文件怎么发送
    如果您想向腾讯云服务器发送文件,您可以按照以下步骤操作: 打开腾讯云服务器的客户端(例如 ChatGPT Client)。 选择您要发送的文件,并输入接收方的 URL。 如果您需要向接收方发送消息,则可以在文件名称下方输入消息文本。 点...
    99+
    2023-10-27
    腾讯 服务器 文件
  • 服务器日志分析怎么看
    服务器日志是记录服务器活动的文件,包含了服务器的各种操作、访问记录等信息。对于服务器日志的分析,可以从以下几个方面进行:1. 访问量...
    99+
    2023-06-10
    服务器日志分析 服务器
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作