Observability:将 OpenTelemetry 添加到你的 Flask 应用程序

打印 上一主题 下一主题

主题 802|帖子 802|积分 2406

作者:来自 Elastic jessgarson

待办事项列表可以资助管理与假期计划干系的所有购物和任务。使用 Flask,你可以轻松创建待办事项列表应用程序,并使用 Elastic 作为遥测后端,通过 OpenTelemetry 对其进行监控。
Flask 是一个轻量级的 Python Web 框架,可让你轻松创建应用程序。OpenTelemetry 是一个开源的、与供应商无关的可观察性框架,它提供跨不同服务宁静台的同一监控功能,允许与各种后端系统无缝集成。
这篇文章将引导你使用 OpenTelemetry Python 的 Elastic Distribution 来监控 Flask 中内置的待办事项列表应用程序。本文中概述的示例的完整代码可以在此处找到。

如何将 Elastic 连接到 OpenTelemetry?

OpenTelemetry 的一大优点是它可以灵活地与你的应用程序集成。使用 Elastic 作为遥测后端。你有几个选择;你可以使用 OpenTelemetry 收集器(官方 OpenTelmetry 语言客户端)连接到 APM(AWS Lambda 收集器导出器)。我们的文档可让你详细了解将 OpenTelemetry 连接到 Elastic 的选项。
你将使用 OpenTelemetry Python 的 Elastic Distribution 作为本文中的示例。此库是 OpenTelemetry Python 的一个版本,具有附加功能并支持将 OpenTelemetry 与 Elastic 集成。需要留意的是,此包目前处于预览阶段,不应在生产环境中使用。


使用 Flask 创建待办事项列表应用程序

在监控应用程序之前,你必须先创建它。本文将引导你创建一个简朴的待办事项列表应用程序来资助你跟踪任务。完成应用程序后,它将如下所示:

开始之前,你需要创建一个捏造环境。创建捏造环境后,你需要安装所需的软件包。
  1. pip install Flask Flask-SQLAlchemy
复制代码
安装所需的软件包后,你必须导入必要的软件包和方法,设置 Flask 应用程序,并使用 SQLalachemy 设置 SQLite 数据库。之后,你将定义一个数据库模型来存储和列出任务项。你还需要初始化应用程序以使用 SQLalcamey,并通过创建所需的表来初始化数据库。
  1. from flask import Flask, request, render_template_string, redirect, url_for
  2. from flask_sqlalchemy import SQLAlchemy
  3. from sqlalchemy.orm import Mapped, mapped_column
  4. app = Flask(__name__)
  5. app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///tasks.db"
  6. db = SQLAlchemy()
  7. # Define a database model named Task for storing task data
  8. class Task(db.Model):
  9.    id: Mapped[int] = mapped_column(db.Integer, primary_key=True)
  10.    description: Mapped[str] = mapped_column(db.String(256), nullable=False)
  11. # Initialize SQLAlchemy with the configured Flask application
  12. db.init_app(app)
  13. # Initialize the database within the application context
  14. with app.app_context():
  15.    db.create_all()  # Creates all tables
复制代码
你如今可以设置 HTML 模板来创建待办事项列表应用程序的前端,包括用于添加任务的内联 CSS 和表单内容。你还将定义用于列出现有任务和删除任务的其他功能。
  1. HOME_HTML = """
  2. <!doctype html>
  3. <html lang="en">
  4. <head>
  5. <meta charset="UTF-8">
  6. <title>To-Do List</title>
  7. <style>
  8.    body {
  9.      font-family: Arial, sans-serif;
  10.      background-color: #f4f4f9;
  11.      margin: 40px auto;
  12.      padding: 20px;
  13.      max-width: 600px;
  14.      box-shadow: 0 0 10px rgba(0,0,0,0.1);
  15.    }
  16.    h1 {
  17.      color: #333;
  18.    }
  19.    form {
  20.      margin-bottom: 20px;
  21.    }
  22.    input[type="text"] {
  23.      padding: 10px;
  24.      width: calc(100% - 22px);
  25.      margin-bottom: 10px;
  26.    }
  27.    input[type="submit"] {
  28.      background-color: #5cb85c;
  29.      border: none;
  30.      color: white;
  31.      padding: 10px 20px;
  32.      text-transform: uppercase;
  33.      letter-spacing: 0.05em;
  34.      cursor: pointer;
  35.    }
  36.    ul {
  37.      list-style-type: none;
  38.      padding: 0;
  39.    }
  40.    li {
  41.      position: relative;
  42.      padding: 8px;
  43.      background-color: #fff;
  44.      border-bottom: 1px solid #ddd;
  45.    }
  46.    .delete-button {
  47.      position: absolute;
  48.      right: 10px;
  49.      top: 10px;
  50.      background-color: #ff6347;
  51.      color: white;
  52.      border: none;
  53.      padding: 5px 10px;
  54.      border-radius: 5px;
  55.      cursor: pointer;
  56.    }
  57. </style>
  58. </head>
  59. <body>
  60. <h1>To-Do List</h1>
  61. <form action="/add" method="post">
  62.    <input type="text" name="task" placeholder="Add new task">
  63.    <input type="submit" value="Add Task">
  64. </form>
  65. <ul>
  66.    {% for task in tasks %}
  67.      <li>{{ task.description }} <button class="delete-button" onclick="location.href='/delete/{{ task.id }}'">Delete</button></li>
  68.    {% endfor %}
  69. </ul>
  70. </body>
  71. </html>
  72. """
复制代码
如今,你可以创建路由,以便在加载时在应用程序上表现待办事项列表任务、添加新任务和删除任务。
/ 路由允许你定义当有人访问应用程序主页时返回哪些数据;在这种环境下,你从数据库输入的所有待办事项列表任务都将表如今屏幕上。
对于添加新任务,当你在应用程序上填写表单以添加和提交新任务时,/add 路由会将此新任务生存在数据库中。生存任务后,它会将你送回主页,以便他们可以看到添加了新任务的列表。
你还将为 /delete 定义一个路由,它描述了当你删除任务时会发生什么(在本例中,当你单击任务旁边的删除按钮时)。然后,应用程序会从数据库中删除该任务。
末了,你将添加逻辑来运行应用程序。
  1. # Define route for the home page to display tasks
  2. @app.route("/", methods=["GET"])
  3. def home():
  4.    tasks = Task.query.all()  # Retrieve all tasks from the database
  5.    return render_template_string(
  6.        HOME_HTML, tasks=tasks
  7.    )  # Render the homepage with tasks listed
  8. # Define route to add new tasks from the form submission
  9. @app.route("/add", methods=["POST"])
  10. def add():
  11.    task_description = request.form["task"]  # Extract task description from form data
  12.    new_task = Task(description=task_description)  # Create new Task instance
  13.    db.session.add(new_task)  # Add new task to database session
  14.    db.session.commit()  # Commit changes to the database
  15.    return redirect(url_for("home"))  # Redirect to the home page
  16. # Define route to delete tasks based on task ID
  17. @app.route("/delete/<int:task_id>", methods=["GET"])
  18. def delete(task_id: int):
  19.    task_to_delete = Task.query.get(task_id)  # Get task by ID
  20.    if task_to_delete:
  21.        db.session.delete(task_to_delete)  # Remove task from the database session
  22.        db.session.commit()  # Commit the change to the database
  23.    return redirect(url_for("home"))  # Redirect to the home page
  24. # Check if the script is the main program and run the app
  25. if __name__ == "__main__":
  26.    app.run()  # Start the Flask application
复制代码
要在本地运行你的应用程序,你可以在终端中运行以下下令。
  1. flask run -p 5000
复制代码

检测应用程序

检测是指向应用程序添加可观察性功能以收集遥测数据,例如跟踪、指标和日志。在数据中,你可以看到正在运行的依赖服务;例如,你可以看到正在构建的应用程序(在此示例中)使用 SQLite。你还可以跟踪请求在分布式系统中跨度移动的各种服务,并检察有关在分布式系统中运行的历程的定量信息。

自动检测与手动检测

你有两种检测应用程序的选项:自动检测手动检测
自动检测会修改应用程序类的字节码以将监控代码插入到应用程序中。使用自动检测,你可以轻松监控应用程序,而无需担心创建自定义监控。这是一种开始监控应用程序或向现有应用程序添加监控功能的好方法。
手动检测允许你向应用程序添加自定义代码段以收集和传输遥测数据。如果你正在寻找自定义或发现自动检测仅涵盖你需要的部分内容,则它很有用。

向你的待办事项列表应用程序添加自动检测

要向你的 Flask 应用程序添加自动检测,你无需添加任何其他监控代码。当你运行应用程序时,OpenTelemetry 将通过 Python 路径自动添加所需的代码。你可以按照以下步骤向你的应用程序添加自动检测。

步骤 1:安装所需的软件包

首先,你需要安装检测所需的软件包。
  1. pip install elastic-opentelemetry opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlp opentelemetry-instrumentation-flask
  2. opentelemetry-bootstrap --action=install
复制代码

第 2 步:设置本地环境变量

如今,你可以设置环境变量以包罗应用程序的服务名称、API 密钥和弹性主机端点。
  1. export OTEL_RESOURCE_ATTRIBUTES=service.name=todo-list-app
  2. export OTEL_EXPORTER_OTLP_HEADERS="Authorization=ApiKey <your-api-key>"
  3. export OTEL_EXPORTER_OTLP_ENDPOINT=https://<your-elastic-url>
复制代码

步骤 3:运行应用程序

要使用 OpenTelemetry 运行你的应用程序,你需要在终端中运行以下下令:
  1. opentelemetry-instrument flask run -p 5000
复制代码
此时,如果你检察 Kibana,其中表现 “observability”  紧接着 “services”,你应该会看到你的服务列为你在环境变量中设置的服务名称。

如果你点击 service 名称,你应该会看到一个仪表板,其中包罗待办事项列表应用程序的可观察性数据。下面的 “Transactions” 部分中的屏幕截图表现了你可以接纳的操作,例如在使用 GET 方法加载应用程序时加载所有待办事项列表项,以及使用 POST 方法将新项目添加到待办事项列表中。


向你的待办事项列表应用程序添加手动检测

由于手动检测允许你根据自己的喜欢自定义检测,因此你必须将自己的监控代码添加到你的应用程序中才能启动并运行。本节的完整代码示例可在此处找到。
首先,你需要通过设置以下环境变量来更新你的服务名称:
  1. export OTEL_RESOURCE_ATTRIBUTES=service.name=mi-todo-list-app
复制代码
如今你已经更新了 service 名称,你需要更新导入语句以包罗更多功能,用于监控应用程序、剖析环境变量以及确保标头格式精确。
  1. import os
  2. from flask import Flask, request, render_template_string, redirect, url_for
  3. from flask_sqlalchemy import SQLAlchemy
  4. from sqlalchemy.orm import Mapped, mapped_column
  5. from opentelemetry import trace, metrics
  6. from opentelemetry.instrumentation.flask import FlaskInstrumentor
  7. from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor
  8. from opentelemetry.sdk.resources import Resource
  9. from opentelemetry.sdk.trace import TracerProvider
  10. from opentelemetry.sdk.trace.export import BatchSpanProcessor
  11. from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
  12. from opentelemetry.sdk.metrics import MeterProvider
  13. from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
  14. from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import OTLPMetricExporter
  15. # Get environment variables
  16. service_name = os.getenv("OTEL_RESOURCE_ATTRIBUTES", "service.name=todo-flask-app").split("=")[-1]
  17. otlp_endpoint = os.getenv("OTEL_EXPORTER_OTLP_ENDPOINT")
  18. otlp_headers = os.getenv("OTEL_EXPORTER_OTLP_HEADERS")
  19. if not otlp_endpoint or not otlp_headers:
  20.    raise ValueError("OTEL_EXPORTER_OTLP_ENDPOINT and OTEL_EXPORTER_OTLP_HEADERS must be set in environment variables")
  21. # Ensure headers are properly formatted for gRPC metadata
  22. headers_dict = dict(item.split(":", 1) for item in otlp_headers.split(",") if ":" in item)
复制代码
如今,你将需要设置你的应用程序以生成、批处理和发送跟踪数据到 Elastic,从而深入了解你的应用程序的运行和性能。
  1. # Configure tracing provider and exporter
  2. resource = Resource(attributes={
  3.     "service.name": service_name
  4. })
  5. trace.set_tracer_provider(TracerProvider(resource=resource))
  6. tracer_provider = trace.get_tracer_provider()
  7. otlp_trace_exporter = OTLPSpanExporter(
  8.     endpoint=otlp_endpoint,
  9.     headers=headers_dict,
  10. )
  11. span_processor = BatchSpanProcessor(otlp_trace_exporter)
  12. tracer_provider.add_span_processor(span_processor)
复制代码
你如今可以设置用于捕获遥测数据的框架。你需要创建跟踪器、计量器和计数器。跟踪器为分布式跟踪创建跨度,资助了解分布式系统的流程和性能问题。计量器和计数器捕获操作指标(如计数请求)对于生产环境中的性能监控和警报至关重要。你的指标设置可确保这些指标得到适当批处理并发送到 Elastic 进行分析。
  1. # Create a tracer
  2. tracer = trace.get_tracer(__name__)
  3. # Configure metrics provider and exporter
  4. otlp_metric_exporter = OTLPMetricExporter(
  5.     endpoint=otlp_endpoint,
  6.     headers=headers_dict,
  7. )
  8. metric_reader = PeriodicExportingMetricReader(otlp_metric_exporter)
  9. meter_provider = MeterProvider(resource=resource, metric_readers=[metric_reader])
  10. metrics.set_meter_provider(meter_provider)
  11. # Create a meter
  12. meter = metrics.get_meter(__name__)
  13. requests_counter = meter.create_counter(
  14.     name="requests_count",
  15.     description="Number of requests received",
  16.     unit="1",
  17. )
复制代码
你将需要使用 Flask 和 SQLite 来获取有关可观察性后端(即 Elastic)中的这两项服务的信息。
  1. FlaskInstrumentor().instrument_app(app)
  2. with app.app_context():
  3.     SQLAlchemyInstrumentor().instrument(engine=db.engine)
复制代码
如今,你可以为每个应用程序路由配备跟踪和指标收集功能。这样你就可以定义向每个路由(GET、POST 和 DELETE)添加哪些跟踪和指标,从而让你能够了解运营绩效,同时还可以收集有关用户交互和系统服从的宝贵数据。
  1. # Define route for the home page to display tasks
  2. @app.route("/", methods=["GET"])
  3. def home():
  4.    with app.app_context():
  5.        with tracer.start_as_current_span("home-request"):
  6.            requests_counter.add(1, {"method": "GET", "endpoint": "/"})
  7.            tasks = Task.query.all()  # Retrieve all tasks from the database
  8.            return render_template_string(
  9.                HOME_HTML, tasks=tasks
  10.            )  # Render the homepage with tasks listed
  11. # Define route to add new tasks from the form submission
  12. @app.route("/add", methods=["POST"])
  13. def add():
  14.    with app.app_context():
  15.        with tracer.start_as_current_span("add-task"):
  16.            requests_counter.add(1, {"method": "POST", "endpoint": "/add"})
  17.            task_description = request.form["task"]  # Extract task description from form data
  18.            new_task = Task(description=task_description)  # Create new Task instance
  19.            db.session.add(new_task)  # Add new task to database session
  20.            db.session.commit()  # Commit changes to the database
  21.            return redirect(url_for("home"))  # Redirect to the home page
  22. # Define route to delete tasks based on task ID
  23. @app.route("/delete/<int:task_id>", methods=["GET"])
  24. def delete(task_id: int):
  25.    with app.app_context():
  26.        with tracer.start_as_current_span("delete-task"):
  27.            requests_counter.add(1, {"method": "GET", "endpoint": f"/delete/{task_id}"})
  28.            task_to_delete = Task.query.get(task_id)  # Get task by ID
  29.            if task_to_delete:
  30.                db.session.delete(task_to_delete)  # Remove task from the database session
  31.                db.session.commit()  # Commit the change to the database
  32.            return redirect(url_for("home"))  # Redirect to the home page
复制代码
由于你已将自定义监控代码应用到你的应用程序中,因此你可以像第一次创建它时一样在终端中运行。
  1. flask run -p 5000
复制代码
如今你应该可以在 “Services” 下看到你的数据,其方式与自动检测中相同。

结论

由于 OpenTelemetry 的一大特色是其可定制性,因此这只是你如何使用 Elastic 作为 OpenTelemetry 后端的开始。下一步,请探索我们的 OpenTelemetry 演示应用程序,以了解如何在更现实的应用程序中运用 Elastic。你也可以将此应用程序摆设到服务器。
此示例的完整代码可在此处找到。如果你基于此博客构建了任何内容,大概你对我们的论坛和社区 Slack 频道有疑问,请告诉我们。

原文:Dec 6th, 2024: [EN] Adding OpenTelemetry to Your Flask Application - Advent Calendar - Discuss the Elastic Stack

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

立聪堂德州十三局店

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表