删除Airflow任务日志

时间:2017-04-21 17:29:12

标签: airflow

我正在运行5个DAG,这些DAG在一个月内在base_log_folder内生成了大约6GB的日志数据。我刚刚添加了remote_base_log_folder但似乎并未排除记录到base_log_folder

是否有自动删除旧日志文件,旋转它们或强制气流不能仅在远程存储中登录磁盘(base_log_folder)?

8 个答案:

答案 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 个原因抢占磁盘空间

  • 1.气流调度器日志文件 2.mysql二进制日志【主要】 3. xcom 表记录。

为了定期清理,我设置了一个每天运行的 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 中测试。