Airflow 删除任务日志
我正在运行5个DAG,它们在Airflow 删除任务日志,airflow,Airflow,我正在运行5个DAG,它们在base\u log\u文件夹中在一个月内总共生成了大约6GB的日志数据。我刚刚添加了一个remote\u base\u log\u文件夹,但它似乎不排除登录到base\u log\u文件夹 是否存在自动删除旧日志文件、旋转它们或强制不登录磁盘(基本日志文件夹)的方法仅在远程存储中?我不认为存在旋转机制,但您可以将它们存储在S3或google云存储中,如下所述:Airflow维护人员不认为截断日志是Airflow核心逻辑的一部分,请看,在本期中,维护人员建议更改日志级
base\u log\u文件夹中在一个月内总共生成了大约6GB的日志数据。我刚刚添加了一个remote\u base\u log\u文件夹
,但它似乎不排除登录到base\u log\u文件夹
是否存在自动删除旧日志文件、旋转它们或强制不登录磁盘(基本日志文件夹)的方法仅在远程存储中?我不认为存在旋转机制,但您可以将它们存储在S3或google云存储中,如下所述:Airflow维护人员不认为截断日志是Airflow核心逻辑的一部分,请看,在本期中,维护人员建议更改日志级别以避免太多日志数据
在PR中,我们可以学习如何在afflow.cfg
中更改日志级别
祝你好运。请参考
这个插件有DAG,可以杀死暂停的任务和日志清理。
您可以掌握这些概念,并提出一个新的DAG,它可以根据您的要求进行清理。我们通过实现自己的FileTaskHandler
来删除任务日志,然后在aiffort.cfg
中指向它。因此,我们覆盖默认的LogHandler,只保留N个任务日志,而不安排额外的DAG
我们使用的是气流==1.10.1
[core]
logging_config_class = log_config.LOGGING_CONFIG
log\u config.LOGGING\u config
BASE_LOG_FOLDER = conf.get('core', 'BASE_LOG_FOLDER')
FOLDER_TASK_TEMPLATE = '{{ ti.dag_id }}/{{ ti.task_id }}'
FILENAME_TEMPLATE = '{{ ti.dag_id }}/{{ ti.task_id }}/{{ ts }}/{{ try_number }}.log'
LOGGING_CONFIG = {
'formatters': {},
'handlers': {
'...': {},
'task': {
'class': 'file_task_handler.FileTaskRotationHandler',
'formatter': 'airflow.job',
'base_log_folder': os.path.expanduser(BASE_LOG_FOLDER),
'filename_template': FILENAME_TEMPLATE,
'folder_task_template': FOLDER_TASK_TEMPLATE,
'retention': 20
},
'...': {}
},
'loggers': {
'airflow.task': {
'handlers': ['task'],
'level': JOB_LOG_LEVEL,
'propagate': False,
},
'airflow.task_runner': {
'handlers': ['task'],
'level': LOG_LEVEL,
'propagate': True,
},
'...': {}
}
}
文件任务处理程序。文件任务旋转处理程序
import os
import shutil
from airflow.utils.helpers import parse_template_string
from airflow.utils.log.file_task_handler import FileTaskHandler
class FileTaskRotationHandler(FileTaskHandler):
def __init__(self, base_log_folder, filename_template, folder_task_template, retention):
"""
:param base_log_folder: Base log folder to place logs.
:param filename_template: template filename string.
:param folder_task_template: template folder task path.
:param retention: Number of folder logs to keep
"""
super(FileTaskRotationHandler, self).__init__(base_log_folder, filename_template)
self.retention = retention
self.folder_task_template, self.folder_task_template_jinja_template = \
parse_template_string(folder_task_template)
@staticmethod
def _get_directories(path='.'):
return next(os.walk(path))[1]
def _render_folder_task_path(self, ti):
if self.folder_task_template_jinja_template:
jinja_context = ti.get_template_context()
return self.folder_task_template_jinja_template.render(**jinja_context)
return self.folder_task_template.format(dag_id=ti.dag_id, task_id=ti.task_id)
def _init_file(self, ti):
relative_path = self._render_folder_task_path(ti)
folder_task_path = os.path.join(self.local_base, relative_path)
subfolders = self._get_directories(folder_task_path)
to_remove = set(subfolders) - set(subfolders[-self.retention:])
for dir_to_remove in to_remove:
full_dir_to_remove = os.path.join(folder_task_path, dir_to_remove)
print('Removing', full_dir_to_remove)
shutil.rmtree(full_dir_to_remove)
return FileTaskHandler._init_file(self, ti)
我知道这听起来很野蛮,但是你试过把base\u log\u文件夹
指向/dev/null
?我使用气流作为容器的一部分,因此我也不关心文件,只要记录器也将管道连接到STDOUT
不过,我不确定这对S3有多好。对于您的具体问题,我有一些建议。
对于这些,您将始终需要一个专门的日志记录配置,如以下回答中所述:
-
自动删除旧日志文件并对其进行旋转
我还没有使用Python标准库中的TimedRotatingFileHandler
的任何实际经验,但您可以尝试一下:
它不仅提供根据时间间隔旋转文件,而且如果指定backupCount
参数,它甚至会删除旧的日志文件:
如果backupCount
为非零,则最多将保留backupCount
文件,如果发生滚动时将创建更多文件,则删除最旧的文件。删除逻辑使用间隔来确定要删除的文件,因此更改间隔可能会留下旧文件
这听起来很像是解决第一个问题的最佳方案
-
强制不在磁盘(基本日志文件夹)上登录,而仅在远程存储中登录
在这种情况下,您应该指定日志配置,这样您就不会有任何写入文件的日志处理程序,即删除所有FileHandlers
相反,尝试查找直接将输出发送到远程地址的日志处理程序。
例如,哪些直接登录到ElasticSearch,但需要在日志调用中添加一些额外字段。
或者,编写自己的处理程序类,并让它继承Python标准库的
最后一个建议是将TimedRotatingFileHandler
和setup ElasticSearch与FileBeat结合使用,这样您就可以将日志存储在ElasticSearch中(即远程),但是您不会在Airflow磁盘上存储大量日志,因为它们将被TimedRotatingFileHandler的备份保留策略删除通常apache Airflow会因为以下三个原因占用磁盘空间
- 1。气流调度器记录文件
2.mysql二进制日志[主要]
3.xcom表格记录。
为了定期清理,我设置了一个dag,每天运行,清理二进制日志,截断xcom表以释放磁盘空间
您可能还需要安装[pip install mysql connector python]。
为了清理调度程序日志文件,我每周手动删除它们两次,以避免由于某些原因需要删除日志的风险
我通过[sudo rm-rd/logs/]命令清理日志文件
下面是我的python代码供参考
'
"""Example DAG demonstrating the usage of the PythonOperator."""
from airflow import DAG
from airflow.operators.python import PythonOperator
from datetime import datetime, timedelta
from airflow.utils.dates import days_ago
from airflow.operators.bash import BashOperator
from airflow.providers.postgres.operators.postgres import PostgresOperator
args = {
'owner': 'airflow',
'email_on_failure':True,
'retries': 1,
'email':['Your Email Id'],
'retry_delay': timedelta(minutes=5)
}
dag = DAG(
dag_id='airflow_logs_cleanup',
default_args=args,
schedule_interval='@daily',
start_date=days_ago(0),
catchup=False,
max_active_runs=1,
tags=['airflow_maintenance'],
)
def truncate_table():
import mysql.connector
connection = mysql.connector.connect(host='localhost',
database='db_name',
user='username',
password='your password',
auth_plugin='mysql_native_password')
cursor = connection.cursor()
sql_select_query = """TRUNCATE TABLE xcom"""
cursor.execute(sql_select_query)
connection.commit()
connection.close()
print("XCOM Table truncated successfully")
def delete_binary_logs():
import mysql.connector
from datetime import datetime
date = datetime.today().strftime('%Y-%m-%d')
connection = mysql.connector.connect(host='localhost',
database='db_name',
user='username',
password='your_password',
auth_plugin='mysql_native_password')
cursor = connection.cursor()
query = 'PURGE BINARY LOGS BEFORE ' + "'" + str(date) + "'"
sql_select_query = query
cursor.execute(sql_select_query)
connection.commit()
connection.close()
print("Binary logs deleted successfully")
t1 = PythonOperator(
task_id='truncate_table',
python_callable=truncate_table, dag=dag
)
t2 = PythonOperator(
task_id='delete_binary_logs',
python_callable=delete_binary_logs, dag=dag
)
t2 << t1
'
“”“演示PythonOperator用法的示例DAG。”“”
从气流导入DAG
从afflow.operators.python导入PythonOperator
从datetime导入datetime,timedelta
从airflow.utils.dates导入天\u
从afflow.operators.bash导入bash操作符
从afflow.providers.postgres.operators.postgres导入PostgresOperator
args={
“所有者”:“气流”,
“失败时发送电子邮件”:True,
“重试”:1,
“电子邮件”:[“您的电子邮件Id”],
“重试延迟”:时间增量(分钟=5)
}
dag=dag(
dag_id='airflow_logs_cleanup',
默认值_args=args,
计划时间间隔=“@daily”,
开始日期=日前(0),
catchup=False,
最大有效运行次数=1,
标签=['airflow_maintenance'],
)
def truncate_表():
导入mysql.connector
connection=mysql.connector.connect(host='localhost',
数据库='db\u name',
user='username',
password='your password',
auth\u plugin='mysql\u native\u password')
cursor=connection.cursor()
sql\u选择\u查询=“截断表xcom”“”
cursor.execute(sql\u select\u查询)
commit()连接
连接。关闭()
打印(“XCOM表已成功截断”)
def delete_binary_logs():
导入mysql.connector
从日期时间导入日期时间
date=datetime.today().strftime(“%Y-%m-%d”)
connection=mysql.connector.connect(host='localhost',
数据库='db\u name',