我正在运行5个DAG,这些DAG在一个月内在base_log_folder
内生成了大约6GB的日志数据。我刚刚添加了remote_base_log_folder
但似乎并未排除记录到base_log_folder
。
是否有自动删除旧日志文件,旋转它们或强制气流不能仅在远程存储中登录磁盘(base_log_folder)?
答案 0 :(得分:10)
请参阅https://github.com/teamclairvoyant/airflow-maintenance-dags
此插件具有可以杀死暂停任务和日志清理的DAG。 您可以获取概念,并可以根据您的要求提供可以清理的新DAG。
答案 1 :(得分:2)
我们通过实现自己的FileTaskHandler
,然后在airflow.cfg
中指向任务日志来删除任务日志。因此,我们将覆盖默认的LogHandler以仅保留N个任务日志,而无需安排其他DAG。
我们正在使用Airflow==1.10.1
。
[core]
logging_config_class = log_config.LOGGING_CONFIG
log_config.LOGGING_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,
},
'...': {}
}
}
file_task_handler.FileTaskRotationHandler
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)
答案 2 :(得分:1)
气流维护者不认为截断日志是气流核心逻辑的一部分,看this,然后在本期中,维护者建议更改LOG_LEVEL,避免过多的日志数据。
在this PR中,我们可以了解如何更改airflow.cfg
中的日志级别。
答案 3 :(得分:1)
我知道这听起来很野蛮,但是您是否尝试过将base_log_folder
指向/dev/null
?我将Airflow用作容器的一部分,所以我也不关心文件,只要记录器管道也连接到STDOUT
。
不确定该如何与S3配合使用。
答案 4 :(得分:0)
我不认为存在轮换机制,但您可以将其存储在S3或Google云存储中,如下所述:https://airflow.incubator.apache.org/configuration.html#logs
答案 5 :(得分:0)
对于您的具体问题,我有一些建议。 对于这些用户,您将始终需要如此答案中所述的专用日志记录配置:https://stackoverflow.com/a/54195537/2668430
自动删除旧日志文件并对其进行轮换
对于Python标准库中的TimedRotatingFileHandler
,我还没有任何实践经验,但是您可以尝试一下:
https://docs.python.org/3/library/logging.handlers.html#timedrotatingfilehandler
它不仅可以根据时间间隔轮换文件,而且,如果您指定了backupCount
参数,它甚至会删除旧的日志文件:
如果
backupCount
不为零,则最多将保留backupCount
个文件,如果发生翻转时将创建更多文件,则最早的文件将被删除。删除逻辑使用间隔来确定要删除的文件,因此更改间隔可能会使旧文件无处不在。
听起来像是第一个问题的最佳解决方案。
强制气流不登录磁盘(base_log_folder),而仅登录远程存储?
在这种情况下,您应该以这样的方式指定日志记录配置: 没有任何写入文件的日志处理程序,即删除所有FileHandlers
。
相反,尝试查找将输出直接发送到远程地址的日志处理程序。 例如。 CMRESHandler直接登录到ElasticSearch,但在日志调用中需要一些额外的字段。 另外,编写您自己的处理程序类,并使其继承自Python标准库的HTTPHandler。
最后的建议是将TimedRotatingFileHandler
和设置ElasticSearch以及FileBeat结合在一起,这样您就可以将日志存储在ElasticSearch中(即远程),但不会存储大量的日志。登录到您的Airflow磁盘上,因为它们将被backupCount
的{{1}}保留策略删除。
答案 6 :(得分:0)
通常 apache 气流会由于 3 个原因抢占磁盘空间
为了定期清理,我设置了一个每天运行的 dag 并清理二进制日志并截断 xcom 表以腾出磁盘空间 您可能还需要安装 [pip install mysql-connector-python]。 为了清理调度程序日志文件,我会在一周内手动删除它们两次,以避免因某些原因需要删除日志的风险。
我通过 [sudo rm -rd 气流/日志/] 命令清理日志文件。
以下是我的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
'
答案 7 :(得分:0)
我很惊讶,但它对我有用。更新您的配置如下:
base_log_folder=""
在 minio 和 s3 中测试。