从“气流数据分析”部分创建电子邮件报告

时间:2020-07-02 11:36:32

标签: airflow

我最近使用了一些气流,现在我的dag已启动并运行,我已经在UI的“数据分析”部分中查看了一些数据。 制作了一些图表,一些表充满了数据。 我希望能够每周一次通过电子邮件向我发送这些图表和数据,这样我就可以对自己的不同dag运行和任务进行一些定期的全局更新,而不仅仅是每次运行结束时都显示成功或失败的电子邮件。

有什么方便的方法吗?还是我必须使用jinja模板电子邮件操作符和可怕的SQLAlchemy语法来构建自定义dag,以从数据库中重新提取数据?

2 个答案:

答案 0 :(得分:1)

据我所知,没有什么“开箱即用”的功能可以满足您的需求;您可能对问题的“我必须建立一个自定义dag […]”部分是正确的。幸运的是,由于您是 Airflow,您可以利用其代码库来提供帮助:

from airflow import models, settings


def python_task(**context):
    chart_label = context.params["chart_label"]
    query_filters = [models.Chart.label == chart_label]

    session = settings.Session()
    chart_object = session.query(models.Chart).filter(*query_filters).first()

    [...] build and send the email [...]

您可能希望查看Airflow源代码,特别是电子邮件处理部分和界面呈现。请注意,如果您可以使任务相对抽象,则可以很容易地重用它。

答案 1 :(得分:0)

所以我找到了某种解决方案。如果有更好的方法,请随时评论我的工作方式。我很高兴来到这里

我创建了一个静态函数来从图表中恢复数据:

from airflow import settings

def get_data_profilling_data( chart_label):
    """
    Get an array containing data from a data profilling chart.

    Args: 
        chart_label: a string that is the name of a an available chart in Data Profiling section.
        session(None, optional): Not in use.
    Returns:
        A list of tuple with first element representing the header of column.
    """
    import logging
    query_filters = [models.Chart.label == chart_label]
    session = settings.Session()
    # Query database to get a chart object.
    chart_object = session.query(models.Chart).filter(*query_filters).first()

    # Replace useless caracter in query and replace % by %% so it's not interpreted by SQLAlchemy
    # Also add a ; at the end of the statement.
    sql="{}{}".format(chart_object.sql.replace('\n', ' ').replace('\r',' ').replace('%','%%'), ';')

    query = session.connection().engine.execute(sql)
    #recover sql request header.
    headers = tuple(query.keys())
    #recover all data
    data  = query.fetchall()
    #close database connection
    #session.connection().close()
    # Add headers to first position in the list
    data.insert(0,headers)
    return data

一旦将其提取,我就使用jinja模板:

    jinja_str = """<!DOCTYPE html>
    <html>
        <head>
        {% if title %}
            <title>{{ title }}</title>
        {% else %}
            <title>Airflow reports</title>
        {% endif %}
        </head>
        <body>
        <table>
        {% if rows %}
            {% for row in rows %}
                {% if loop.index == 1 %}
                    <!-- table header -->
                    <tr>{% for elem in row %}
                            <th>{{ elem }}</th>
                        {% endfor %}</tr>
                {% endif %}
                {% if loop.index > 1 %}
                    <tr>{% for elem in row %}
                        <td>{{ elem }}</td>
                    {% endfor %}</tr>
                {% endif %}
            {% endfor %}
        {% endif %}
        </table>
        </body>
    </html>"""

    def format_data_from_chart(chart, **kwargs):
        data = DagStatic.get_data_profilling_data(chart)
        report_template = Template( jinja_str )
        report_html = report_template.render({"title": chart,"rows":data})
        kwargs["ti"].xcom_push(key='report_html', value=report_html)

这会将使用jinja模板渲染的图表的数据结果推送到xcom中。 现在,我可以使用电子邮件操作员发送邮件了:

    send_report= email_task = EmailOperator(
                                            to='you.mail@mail.com',
                                            task_id='send_report',
                                            subject='Airflow HTML report start_date {{ ds }}',
                                            html_content="{{  ti.xcom_pull(key='report_html') }}",
                                            dag=dag)

希望这会对您有所帮助。如果有更好的方法,请随时评论我的工作方式。我很高兴来到这里