用 logfire 提高应用的可观测性

news2024/11/25 2:50:16

Logfire是由 Pydantic 团队打造的平台, 还有供 app 使用的 library, 我们经常提到对应用要做 LMT(Log, Metrics, Trace),
Logfire 可以用来收集、存储、分析和可视化日志数据和应用性能指标。通过集成日志和度量,Logfire 提供了一个统一的界面来管理应用程序和系统的可观测性.

Logfire 其实是基于 OpenTelemetry构建的,可以使用大量现有工具和基础架构,包括许多常见 Python 包的观测(instrument)。

OpenTelemetry 是一个开源的可观测性框架,用于生成、收集、处理和导出应用程序的分布式追踪、日志和度量数据。
它旨在帮助开发者更好地监控分布式系统中的应用程序性能,并进行故障排查。

OpenTelemetry 是 CNCF(Cloud Native Computing Foundation)的项目,它统一了许多流行的监控和可观测性工具,比如 OpenTracing 和 OpenCensus。
通过 OpenTelemetry,开发者可以在不同的语言和框架中统一地生成可观测性数据(追踪、日志、指标),并将这些数据发送到不同的后端系统进行分析和可视化,如 Prometheus、Grafana、Jaeger、Zipkin 等

OpenTelemetry 的核心概念就是 LMT:

  1. Logs(日志):
    日志记录应用程序在运行时输出的信息,包括错误、状态信息和其他调试数据。

  2. Metrics(度量):
    用于收集关于系统性能的定量数据,例如 CPU 使用率、内存占用、请求延迟等。这些度量帮助监控应用的性能。

  3. Tracing(追踪):
    用于跟踪跨越不同服务或组件的单个请求,帮助你了解整个请求的生命周期。追踪包括多个 span,每个 span 表示一次操作或请求。

Logfire 比 OpenTelemetry 更好用, 我最近用 FastAPI 写一些 LLM 的应用, 将 Logfire 集成到 FastAPI 中用于日志记录和性能度量,可以帮助监控和分析 FastAPI 应用的健康状态和性能表现。可以通过 logfire 做到

  • 收集和发送 FastAPI 的请求日志。
  • 记录异常并发送到 Logfire。
  • 通过 Prometheus 或 Logfire 的度量功能,监控应用的性能指标。

Logfire 与 FastAPI 的集成

1. 安装依赖

Logfire 提供了适用于不同语言的 SDK,首先你需要安装 Logfire 的 Python 客户端库。通常,官方提供的 SDK 可以通过 pip 安装。

pip install logfire

假设 Logfire 提供了一个 SDK 来发送日志和指标,我们会用这个来集成 FastAPI。

2. FastAPI 日志集成

Logfire 的 SDK 一般允许你直接将应用的日志发送到它的后端。我们可以通过 FastAPI 的事件钩子来捕获日志并发送给 Logfire。

首先,配置 Logfire 的客户端实例:

from logfire import LogfireClient
from fastapi import FastAPI, Request
import logging

app = FastAPI()

# 初始化 Logfire 客户端
logfire_client = LogfireClient(api_key="your-logfire-api-key")

# 设置 FastAPI 的 logger
logger = logging.getLogger("fastapi")
logger.setLevel(logging.INFO)

@app.middleware("http")
async def log_requests(request: Request, call_next):
    # 记录请求信息
    response = await call_next(request)

    log_data = {
        "method": request.method,
        "url": str(request.url),
        "status_code": response.status_code,
        "client_ip": request.client.host,
    }
    
    # 将日志发送到 Logfire
    logfire_client.log("Request info", log_data)

    return response

在这个例子中,通过 FastAPI 的 middleware 机制,在每次 HTTP 请求时捕获请求日志,并将其发送到 Logfire 平台。

3. FastAPI 度量集成

除了日志记录,还可以通过 Logfire 记录应用的性能指标,比如响应时间、CPU 和内存使用等。

import time

@app.middleware("http")
async def add_metrics(request: Request, call_next):
    # 记录请求开始时间
    start_time = time.time()

    # 处理请求
    response = await call_next(request)

    # 计算响应时间
    process_time = time.time() - start_time
    logfire_client.metric("request_duration_seconds", process_time)

    # 记录额外度量数据
    metrics_data = {
        "method": request.method,
        "url": str(request.url),
        "status_code": response.status_code,
        "duration": process_time,
    }

    # 将度量数据发送到 Logfire
    logfire_client.log("Request metrics", metrics_data)

    return response

这个 middleware 会计算每次请求的处理时间,并通过 Logfire 的度量功能发送响应时间等性能数据。

4. 异常处理日志

如果 FastAPI 中发生了未捕获的异常,你可以通过全局异常处理器记录日志并将其发送到 Logfire。

from fastapi import HTTPException
from starlette.middleware.errors import ServerErrorMiddleware

@app.exception_handler(HTTPException)
async def http_exception_handler(request: Request, exc: HTTPException):
    # 捕获 HTTP 异常并记录到 Logfire
    logfire_client.log("HTTP Exception", {"status_code": exc.status_code, "detail": exc.detail})
    return JSONResponse(status_code=exc.status_code, content={"detail": exc.detail})

@app.middleware("http")
async def catch_exceptions_middleware(request: Request, call_next):
    try:
        return await call_next(request)
    except Exception as exc:
        logfire_client.log("Unhandled Exception", {"exception": str(exc)})
        raise exc  # 继续抛出异常

5. 可选:Prometheus 度量与 Logfire 集成

你还可以使用 FastAPI 与 Prometheus 结合,然后将 Prometheus 收集的度量数据导入 Logfire。

首先,使用 prometheus-fastapi-instrumentator 进行集成。

pip install prometheus-fastapi-instrumentator

然后在 FastAPI 应用中添加 Prometheus 的指标收集器:

from prometheus_fastapi_instrumentator import Instrumentator

# 初始化 Prometheus 指标收集器
Instrumentator().instrument(app).expose(app)

@app.on_event("startup")
async def on_startup():
    # 如果 Logfire 支持从 Prometheus 获取数据,可以配置 Prometheus 度量推送到 Logfire
    pass

这个配置可以让 Prometheus 采集到 FastAPI 应用的性能数据,并将其推送到 Logfire 平台。

用 Logfire 记录和观测大模型交互的性能

举例如下

#!/usr/bin/env python3
from pydantic import BaseModel
from fastapi import FastAPI
from openai import AsyncOpenAI
import logfire
from async_llm_agent import AsyncLlmAgent
import asyncio
from collections.abc import Iterable
from fastapi.responses import StreamingResponse

# request
class UserData(BaseModel):
    query: str


# response
class UserDetail(BaseModel):
    name: str
    age: int

class MultipleUserData(BaseModel):
    queries: list[str]

app = FastAPI()
agent = AsyncLlmAgent()
#logfire.configure(pydantic_plugin=logfire.PydanticPlugin(record="all"))
logfire.configure(service_name='lazy-llm-agent')
logfire.instrument_pydantic()
logfire.instrument_openai(agent.get_llm_client(), suppress_other_instrumentation=True)
logfire.instrument_fastapi(app)

@app.post("/user", response_model=UserDetail)
async def endpoint_function(data: UserData) -> UserDetail:
    system_prompt = "You are a smart AI assitant"
    user_prompt = f"Extract: `{data.query}`"
    user_detail = await agent.get_object_response(system_prompt, user_prompt, UserDetail)

    return user_detail

@app.post("/many-users", response_model=list[UserDetail])
async def extract_many_users(data: MultipleUserData):
    async def extract_user(query: str):
        system_prompt = "You are a smart AI assitant"
        user_prompt = f"Extract: `{data.query}`"
        user_detail = await agent.get_object_response(system_prompt, user_prompt, UserDetail)

        logfire.info("/User returning", value=user_detail)
        return user_detail

    coros = [extract_user(query) for query in data.queries]
    return await asyncio.gather(*coros)

@app.post("/extract", response_class=StreamingResponse)
async def extract(data: UserData):
    system_prompt = "You are a smart AI assitant"
    user_prompt = f"Extract: `{data.query}`"
    users = await agent.get_objects_response(system_prompt, user_prompt, UserDetail, stream=True)

    async def generate():
        with logfire.span("Generating User Response Objects"):
            async for user in users:
                resp_json = user.model_dump_json()
                logfire.info("Returning user object", value=resp_json)

                yield resp_json

    return StreamingResponse(generate(), media_type="text/event-stream")


def act_as_client(port: int):
    import requests

    response = requests.post(
        f"http://127.0.0.1:{port}/extract",
        json={
            "query": "Alice and Bob are best friends. \
                They are currently 32 and 43 respectively. "
        },
        stream=True,
    )

    for chunk in response.iter_content(chunk_size=1024):
        if chunk:
            print(str(chunk, encoding="utf-8"), end="\n")

if __name__ == "__main__":
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument('--role','-r', action='store', dest='role', help='specify role: client|server')
    parser.add_argument('--port','-p', type=int, action='store', dest='port', default=2024, help='specify listen port')

    args = parser.parse_args()

    if (args.role=="client"):
        act_as_client(args.port)
    else:
        import uvicorn
        uvicorn.run(app, host="localhost", port=args.port)

要点:

  1. 配置Logfire, 注意要先在 https://logfire.pydantic.dev 上注册你的项目, 获取一个 token
logfire.configure(service_name='lazy-llm-agent')
# 上面这行代码配置了 logfire 的 service_name, 其中参数 token 没有显式传入, 因为已经在环境变量中配置了 LOGFIRE_TOKEN=xxx
logfire.instrument_pydantic()
# 上面这行代码配置了logfire,使其记录所有通过pydantic模型进行的数据交换。
  1. 植入监测 Instrumentation:
logfire.instrument_fastapi(app):
# 上面这行代码将FastAPI应用与logfire集成,以便自动记录API请求和响应。
logfire.instrument_openai(self._client, suppress_other_instrumentation=False):
# 上面这行代码将AsyncOpenAI客户端与logfire集成,以便记录与OpenAI API的交互。
  1. 记录日志:
  • 在extract_many_users函数中,logfire.info("/User returning", value=user_detail) 记录了用户详细信息的返回。
  • 在extract函数的generate生成器中,logfire.info("Returning user object", value=resp_json) 记录了流式响应中的用户对象。
  1. 使用Span:
with logfire.span("Generating User Response Objects"):
# 上面的上下文管理器用于创建一个日志跨度,记录生成用户响应对象的时间和细节。

测试步骤

  1. 启动服务端程序
% ./instructor_server.py -r server
  1. 启动客户端程序
% ./instructor_server.py -r client
Logfire project URL: https://logfire.pydantic.dev/walterfan/lazy-rabbit-agent
{"name":"Alice","age":32}
Logfire project URL: https://logfire.pydantic.dev/walterfan/lazy-rabbit-agent
{"name":"Bob","age":43}

这样我们就可以看到我们的应用程序与大模型的交互次数以及所耗费的时间

snapshot

参考链接

  • 参考文章 https://python.useinstructor.com/blog/2024/05/03/fastapi-open-telemetry-and-instructor
  • 上述例子的源码:
    • https://github.com/walterfan/lazy-rabbit-agent/blob/master/example/instructor_logfire.py
    • https://github.com/walterfan/lazy-rabbit-agent/blob/master/example/async_llm_agent.py

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2208906.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

时间序列预测(一)——线性回归(linear regression)

目录 一、原理与目的 1、线性回归基于两个的假设: 2、线性回归的优缺点: 3、线性回归的主要目的是: 二、损失函数(loss function) 1、平方误差损失函数(忽略了噪声误差) 2、均方误差损失函数 三、随…

springboot项目通过maven的profile功能实现通过不同文件夹的方式来组织不同环境配置文件

写在前面 本文看下springboot项目如何通过文件夹的方式来组织不同环境配置文件。 1:正文 一般的我们写springboot项目时配置文件是这个样子的: appliction.yaml --> 通过spring.profiles.activexxx来激活某个指定后缀的配置文件 application-evn1…

【Java学习笔记】多线程

当我们在饭店聚餐时,多人同时吃一道菜的时候很容易发生争抢。例如,上了一道好菜,两个人同时夹这道菜,一人刚伸出筷子,结果伸到的时候菜已经被夹走了。为了避免这种现象,必须等一人 夹完一口后,另…

【大数据技术基础 | 实验一】配置SSH免密登录

文章目录 一、实验目的二、实验要求三、实验原理(一)大数据实验一体机(二)SSH免密认证 四、实验环境五、实验内容和步骤(一)搭建集群服务器(二)添加域名映射(三&#xff…

工业物联网关-ModbusTCP

Modbus-TCP模式把网关视作Modbus从端设备,主端设备可以通过Modbus-TCP协议访问网关上所有终端设备。用户可以自定义多条通道,每条通道可以配置为TCP Server或者TCP Slave。注意,该模式需要指定采集通道,采集通道可以是串口和网口通…

51WORLD携手浙江科技大学,打造智慧校园新标杆

当前,国家教育数字化战略行动扎实推进,高等教育数字化转型步伐加快。 紧抓数字教育发展战略机遇,浙江科技大学联合51WORLD、正方软件股份有限公司(简称:正方软件),共同研发打造浙科大孪生数智校…

为什么很多人宁愿加钱买港版,也不愿买国行 iPhone 16

最近的 iPhone 16 市场,真的是倒反天罡,攻守异形啊。 过去,港版 iPhone 都是性价比的次选,便宜个 10% 都得考虑考虑。但今年,港版 iPhone 16 的价格,反而比国行还贵。 比如,闲鱼上某个卖家&am…

Java消息摘要:MD5验证数据完整性、密码的加密与校验

MD5(Message-Digest Algorithm 5)是一种被广泛使用的密码散列函数,是一种不可逆的加密算法,该算法可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完…

【工具变量】知识产权示范城市DID(2000-2023年)

数据简介:为深入贯彻落实《国家知识产权战略纲要》,强化知识产权治理效能,国家知识产权局制定了《国家知识产权试点、示范城市(城区)评定和管理办法》,知识产权示范城市成为知识产权强国战略落地的城市支撑…

echarts 入门

工作中第一次碰到echarts&#xff0c;当时有大哥。二进宫没办法&#xff0c;只能搞定它。 感觉生活就是这样&#xff0c;不能解决的问题总是会反复出现。通过看视频、查资料&#xff0c;完成了工作要求。写一篇Hello World&#xff0c;进行备查。 基本使用 快速上手 <!DO…

QNAP新手必看!轻松搞定反向代理设置

反向代理是一种服务器配置&#xff0c;允许你通过一个域名或者IP地址来访问不同的内部应用服务。在QNAP NAS上配置反向代理可以提升应用程序的安全性和可访问性。 准备工作 确保QNAP NAS已连接网络并有公网IPv4/IPv6。 确认已启用Web服务 步骤 1&#xff1a;启用Web服务 登…

相机光学(三十九)——光学暗角与机械暗角

1.什么是暗角 在玩摄影一段时间,拍摄一定数量的照片之后,每个人都会不可避免地遇上一个新问题,那就是暗角现象。所谓暗角,是指在拍摄亮度均匀的场景时,画面的四角却出现与实际景物不符的、亮度降低的现象,又被称为“失光“。 2.暗角的成因 (1)边角的成像光线与镜头光轴…

【智能控制】第2章 专家系统,专家控制,模糊关系,模糊推理,专家PID控制

目录 2.1 专家系统 2.1.1 专家系统概述 2.1.2 专家系统构成 2.1.3 专家系统的建立 1&#xff0e;知识库 2&#xff0e;推理机 3&#xff0e;知识的表示 4&#xff0e;专家系统开发语言 5&#xff0e;专家系统建立步骤 第二节 专家控制 2&#xff0e;功能 3 与专家…

三、账号密码存储

使用Playfers存储 Unity本地持久化类Playerprefs使用详解 - PlaneZhong - 博客园 (cnblogs.com) 一、登陆界面切换 1、登陆界面的脚本&#xff08;机制类脚本&#xff09; 在这个UI上挂载一个脚本LoginWnd 先声明一下这个脚本&#xff0c;拖拽 2、在登录模块中调用 这里的l…

华为全联接大会2024 | 聚焦运维智能化,麒麟信安分享“基于大模型的新一代智能运维平台”

2024年9月19日至21日&#xff0c;以“共赢行业智能化”为主题的华为全联接大会2024在上海世博中心盛大召开。麒麟信安受邀出席大会&#xff0c;与全球的思想领袖、商业精英、技术专家和合作伙伴&#xff0c;共同探讨智能化、数字化技术赋能千行万业&#xff0c;把握新机遇&…

第十五章 Java多线程--线程池

目录 一、线程池基础概念 常见的线程池类型&#xff1a; 创建线程池的例子&#xff1a; 注意事项&#xff1a; 二、线程池使用场景 三、JDK自带的构建线程池的方式 1 newFixedThreadPool 2 newSingleThreadExecutor 3 newCachedThreadPool 4 newScheduleThreadPool …

震撼!一句话就让 AI 帮你做 UI 测试,多模态测试智能体 AUITestAgent 横空出世!

美团到店研发平台携手复旦大学周扬帆教授团队&#xff0c;共同开发了智能化终端测试工具AUITestAgent。该工具是第一个能够基于自然语言测试用例&#xff0c;自动化完成终端UI测试驱动、校验全流程的智能化测试工具。仅需输入自然语言形式的测试需求&#xff0c;AUITestAgent通…

福建谷器参加泉州市中小企业数字化转型试点工作启动会

为进一步加快推动试点城市工作,10月9日,泉州市产业数字化转型工作现场会暨2024年中小企业数字化转型试点工作启动会成功举办。出席本次会议的有福建省工业和信息化厅副厅长许永西、泉州市人民政府副市长雷连鸣等领导,及来自国家工业信息安全发展研究中心、中国工业互联网研究院…

newlibc memcpy 存在问题

背景 sdk 中发现 memcpy 函数没有达到预期&#xff0c;执行后&#xff0c;目的地址与源地址中的内容不一致。 复现方法 通过单步调试 memcpy 汇编代码&#xff0c;发现使用了 ldrh 指令&#xff0c;该指令在对 uncacheable memory 同时该 memory 非对齐的情况下&#xff0c;…

高性能计算平台(HPC)如何选型

选型高性能计算平台&#xff08;HPC&#xff09;非常复杂&#xff0c;需要考针对行业的痛点等多个因素进行考虑&#xff0c;来确保平台系统能满足特定行业和应用的需求。下面为大家列举了几个方面&#xff0c;大家可以参考。 1.计算需求 首先需要了解你需要处理的数据类型、计算…