跳转到主要内容

Python AWS X-Ray SDK(SDK)允许Python开发者从其应用程序中记录和发送信息到AWS X-Ray服务。

项目描述

Build Status codecov

:mega: OpenTelemetry Python与AWS X-Ray

AWS X-Ray支持使用OpenTelemetry Python和AWS Distro for OpenTelemetry (ADOT) Collector来检测您的应用程序并发送跟踪数据到X-Ray。OpenTelemetry SDK是行业标准的跟踪检测。它们提供更多检测并拥有更大的社区支持,但可能不具备与X-Ray SDK完全一致的功能。有关在ADOT和X-Ray SDK之间选择更多帮助的信息,请参阅选择ADOT和X-Ray SDK之间的信息

如果您在跟踪Python应用程序时需要额外的功能,请在OpenTelemetry Python Instrumentation存储库中打开一个问题

:mega: Python版本结束支持通知

AWS X-Ray SDK for Python版本>2.11.0已停止支持Python 2.7,3.4,3.5和3.6。

AWS X-Ray Python SDK

Screenshot of the AWS X-Ray console

安装

AWS X-Ray Python SDK 与 Python 3.7、3.8、3.9、3.10 和 3.11 兼容。

使用以下命令安装 SDK(SDK 的非测试依赖项将被安装)。

pip install aws-xray-sdk

要安装 SDK 的测试依赖项,请使用以下命令。

pip install tox

获取帮助

使用以下社区资源获取 SDK 的帮助。我们使用 GitHub 问题来跟踪错误和功能请求。

打开问题

如果您在使用 AWS X-Ray Python SDK 时遇到错误,我们希望听到您的反馈。在打开新问题之前,请搜索 现有问题,看看其他人是否也遇到同样的问题。包括 AWS X-Ray SDK 的版本、Python 语言以及 botocore/boto3(如有适用)。此外,在适当的情况下,包括重放案例。

GitHub 问题旨在用于错误报告和功能请求。有关使用 AWS Python SDK 的帮助和问题,请使用 获取帮助 部分中列出的资源。保持开放问题的列表精简有助于我们及时响应。

文档

开发指南 开发者指南 提供了关于使用 AWS X-Ray 服务的深入指导。API 参考 API 参考 提供了使用 SDK 和模块级别文档的指导。

快速入门

配置

from aws_xray_sdk.core import xray_recorder

xray_recorder.configure(
    sampling=False,
    context_missing='LOG_ERROR',
    plugins=('EC2Plugin', 'ECSPlugin', 'ElasticBeanstalkPlugin'),
    daemon_address='127.0.0.1:3000',
    dynamic_naming='*mysite.com*'
)

开始自定义段/子段

使用上下文管理器进行隐式异常记录

from aws_xray_sdk.core import xray_recorder

with xray_recorder.in_segment('segment_name') as segment:
    # Add metadata or annotation here if necessary
    segment.put_metadata('key', dict, 'namespace')
    with xray_recorder.in_subsegment('subsegment_name') as subsegment:
        subsegment.put_annotation('key', 'value')
        # Do something here
    with xray_recorder.in_subsegment('subsegment2') as subsegment:
        subsegment.put_annotation('key2', 'value2')
        # Do something else 

上下文管理器的异步版本

from aws_xray_sdk.core import xray_recorder

async with xray_recorder.in_segment_async('segment_name') as segment:
    # Add metadata or annotation here if necessary
    segment.put_metadata('key', dict, 'namespace')
    async with xray_recorder.in_subsegment_async('subsegment_name') as subsegment:
        subsegment.put_annotation('key', 'value')
        # Do something here
    async with xray_recorder.in_subsegment_async('subsegment2') as subsegment:
        subsegment.put_annotation('key2', 'value2')
        # Do something else 

默认的 begin/end 函数

from aws_xray_sdk.core import xray_recorder

# Start a segment
segment = xray_recorder.begin_segment('segment_name')
# Start a subsegment
subsegment = xray_recorder.begin_subsegment('subsegment_name')

# Add metadata or annotation here if necessary
segment.put_metadata('key', dict, 'namespace')
subsegment.put_annotation('key', 'value')
xray_recorder.end_subsegment()

# Close the segment
xray_recorder.end_segment()

过采样缓解

要修改子段级别的采样决策,可以使用 xray_recorder.begin_subsegment() 创建继承其直接父级(段或子段)决策的子段,并可以使用 xray_recorder.begin_subsegment_without_sampling() 创建未采样的子段。

以下代码示例演示了根据 Lambda 处理的每个 SQS 消息的采样决策创建已采样或未采样的子段。

from aws_xray_sdk.core import xray_recorder
from aws_xray_sdk.core.models.subsegment import Subsegment
from aws_xray_sdk.core.utils.sqs_message_helper import SqsMessageHelper

def lambda_handler(event, context):

    for message in event['Records']:
        if SqsMessageHelper.isSampled(message):
            subsegment = xray_recorder.begin_subsegment('sampled_subsegment')
            print('sampled - processing SQS message')

        else:
            subsegment = xray_recorder.begin_subsegment_without_sampling('unsampled_subsegment')
            print('unsampled - processing SQS message')
    
    xray_recorder.end_subsegment()   

以下代码示例演示了使用未采样的子段包装下游 AWS SDK 请求。

from aws_xray_sdk.core import xray_recorder, patch_all
import boto3

patch_all()

def lambda_handler(event, context):
    subsegment = xray_recorder.begin_subsegment_without_sampling('unsampled_subsegment')
    client = boto3.client('sqs')
    print(client.list_queues())
    
    xray_recorder.end_subsegment()

捕获

作为装饰器

from aws_xray_sdk.core import xray_recorder

@xray_recorder.capture('subsegment_name')
def myfunc():
    # Do something here

myfunc()

或作为上下文管理器

from aws_xray_sdk.core import xray_recorder

with xray_recorder.capture('subsegment_name') as subsegment:
    # Do something here
    subsegment.put_annotation('mykey', val)
    # Do something more

异步捕获作为装饰器

from aws_xray_sdk.core import xray_recorder

@xray_recorder.capture_async('subsegment_name')
async def myfunc():
    # Do something here

async def main():
    await myfunc()

或作为上下文管理器

from aws_xray_sdk.core import xray_recorder

async with xray_recorder.capture_async('subsegment_name') as subsegment:
    # Do something here
    subsegment.put_annotation('mykey', val)
    # Do something more

使用记录器添加注释/元数据

from aws_xray_sdk.core import xray_recorder

# Start a segment if no segment exist
segment1 = xray_recorder.begin_segment('segment_name')

# This will add the key value pair to segment1 as it is active
xray_recorder.put_annotation('key', 'value')

# Start a subsegment so it becomes the active trace entity
subsegment1 = xray_recorder.begin_subsegment('subsegment_name')

# This will add the key value pair to subsegment1 as it is active
xray_recorder.put_metadata('key', 'value')

if xray_recorder.is_sampled():
    # some expensitve annotations/metadata generation code here
    val = compute_annotation_val()
    metadata = compute_metadata_body()
    xray_recorder.put_annotation('mykey', val)
    xray_recorder.put_metadata('mykey', metadata)

生成 NoOp 跟踪和实体 ID

默认情况下,X-Ray Python SDK 将为未采样的请求生成无操作跟踪和实体 ID,并为采样的请求生成安全的随机跟踪和实体 ID。如果客户希望为所有(采样/未采样)请求启用生成安全的随机跟踪和实体 ID(这适用于将跟踪 ID 注入日志用例),则应将 AWS_XRAY_NOOP_ID 环境变量设置为 False。

禁用 X-Ray

有时,能够禁用特定用例的 X-Ray 可能很有用,无论是为了在任何时候停止 X-Ray 发送跟踪,还是为了测试原本依赖于 X-Ray 仪器包在代码调用之前开始段的代码功能。例如,如果您的应用程序依赖于 XRayMiddleware 仪器传入的 Web 请求,并且您有一个基于该中间件生成的段开始子段的方法,那么在您需要测试该方法时,禁用 X-Ray 对您的单元测试很有用,这样就不会抛出 SegmentNotFound 异常。

有两种方法可以禁用 X-Ray,一种是通过环境变量,另一种是通过 SDKConfig 模块。

通过环境变量禁用

在运行应用程序之前,请确保将环境变量 AWS_XRAY_SDK_ENABLED 设置为 false

通过 SDKConfig 模块禁用

from aws_xray_sdk import global_sdk_config

global_sdk_config.set_sdk_enabled(False)

重要说明

  • 在启用/禁用时,环境变量始终优先于 SDKConfig 模块。如果你的环境变量设置为 false,而你的代码调用 global_sdk_config.set_sdk_enabled(True),X-Ray 仍然会被禁用。

  • 如果在运行时需要再次启用 X-Ray 并确认通过 SDKConfig 模块禁用/启用,你可以在应用程序中运行以下代码

import os
from aws_xray_sdk import global_sdk_config

del os.environ['AWS_XRAY_SDK_ENABLED']
global_sdk_config.set_sdk_enabled(True)

跟踪 AWS Lambda 函数

from aws_xray_sdk.core import xray_recorder

def lambda_handler(event, context):
    # ... some code

    subsegment = xray_recorder.begin_subsegment('subsegment_name')
    # Code to record
    # Add metadata or annotation here, if necessary
    subsegment.put_metadata('key', dict, 'namespace')
    subsegment.put_annotation('key', 'value')

    xray_recorder.end_subsegment()

    # ... some other code

跟踪 ThreadPoolExecutor

import concurrent.futures

import requests

from aws_xray_sdk.core import xray_recorder
from aws_xray_sdk.core import patch

patch(('requests',))

URLS = ['http://www.amazon.com/',
        'http://aws.amazon.com/',
        'http://example.com/',
        'http://www.bilibili.com/',
        'http://invalid-domain.com/']

def load_url(url, trace_entity):
    # Set the parent X-Ray entity for the worker thread.
    xray_recorder.set_trace_entity(trace_entity)
    # Subsegment captured from the following HTTP GET will be
    # a child of parent entity passed from the main thread.
    resp = requests.get(url)
    # prevent thread pollution
    xray_recorder.clear_trace_entities()
    return resp

# Get the current active segment or subsegment from the main thread.
current_entity = xray_recorder.get_trace_entity()
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
    # Pass the active entity from main thread to worker threads.
    future_to_url = {executor.submit(load_url, url, current_entity): url for url in URLS}
    for future in concurrent.futures.as_completed(future_to_url):
        url = future_to_url[future]
        try:
            data = future.result()
        except Exception:
            pass

跟踪 SQL 查询

默认情况下,如果未提供其他值给 .configure(),则支持的所有数据库引擎的 SQL 跟踪流都启用。这些目前是

  • 连接到 Django ORM 的任何引擎。
  • 连接到 SQLAlchemy 的任何引擎。

可以通过发送适当的 stream_sql 值来切换行为,例如

from aws_xray_sdk.core import xray_recorder

xray_recorder.configure(service='fallback_name', stream_sql=True)

修复第三方库

from aws_xray_sdk.core import patch

libs_to_patch = ('boto3', 'mysql', 'requests')
patch(libs_to_patch)

自动模块修复

可以通过提供模块引用给修复函数来递归地修复本地代码库中的完整模块。

from aws_xray_sdk.core import patch

libs_to_patch = ('boto3', 'requests', 'local.module.ref', 'other_module')
patch(libs_to_patch)

xray_recorder.capture() 装饰器应用于给定模块及其所有子模块中的所有函数和类方法。可以通过向修复函数提供一个匹配它们的正则表达式来排除某些文件/模块。

from aws_xray_sdk.core import patch

libs_to_patch = ('boto3', 'requests', 'local.module.ref', 'other_module')
ignore = ('local.module.ref.some_file', 'other_module.some_module\.*')
patch(libs_to_patch, ignore_module_patterns=ignore)

Django

添加 Django 中间件

在 django settings.py 中,使用以下内容。

INSTALLED_APPS = [
    # ... other apps
    'aws_xray_sdk.ext.django',
]

MIDDLEWARE = [
    'aws_xray_sdk.ext.django.middleware.XRayMiddleware',
    # ... other middlewares
]

你可以在 Django 应用程序中的 ‘XRAY_RECORDER’ 命名空间下配置 X-Ray 记录器。对于最小配置,需要指定 'AWS_XRAY_TRACING_NAME',除非它已通过环境变量指定。

XRAY_RECORDER = {
    'AWS_XRAY_TRACING_NAME': 'My application', # Required - the segment name for segments generated from incoming requests
}

有关配置 Django 与 X-Ray 的更多信息,请参阅 API 参考

SQL 跟踪

如果 Django 的 ORM 已修复 - 要么使用设置文件中的 AUTO_INSTRUMENT = True,要么显式调用 patch_db() - 则可以通过更新设置文件中的 STREAM_SQL 变量来启用或禁用 SQL 查询跟踪流。默认情况下启用。

自动修复

也可以通过 Django 设置配置自动模块修复。

XRAY_RECORDER = {
    'PATCH_MODULES': [
        'boto3',
        'requests',
        'local.module.ref',
        'other_module',
    ],
    'IGNORE_MODULE_PATTERNS': [
        'local.module.ref.some_file',
        'other_module.some_module\.*',
    ],
    ...
}

如果还指定了 AUTO_PATCH_PARENT_SEGMENT_NAME,则将创建具有指定名称的段父级,包装自动修复,以便捕获在导入修复时创建的任何悬空子段。

Django 在 Lambda 中

X-Ray 无法在子段上搜索 http 注释。为了启用搜索,中间件将 http 值添加为注释。这允许在 X-Ray 控制台中按如下方式搜索

这可以在设置中使用 URLS_AS_ANNOTATION 进行配置,它有 3 个有效值 LAMBDA - 默认值,如果在 Lambda 环境中运行,则默认使用 URL 作为注释 ALL - 对每个请求都这样做(如果同时在 Lambda 和其他部署中运行,则很有用) NONE - 不对任何请求这样做(以避免触及 50 个注释限制)

annotation.url BEGINSWITH "https://your.url.com/here"

添加 Flask 中间件

from aws_xray_sdk.core import xray_recorder
from aws_xray_sdk.ext.flask.middleware import XRayMiddleware

app = Flask(__name__)

xray_recorder.configure(service='fallback_name', dynamic_naming='*mysite.com*')
XRayMiddleware(app, xray_recorder)

添加 Bottle 中间件(插件)

from aws_xray_sdk.core import xray_recorder
from aws_xray_sdk.ext.bottle.middleware import XRayMiddleware

app = Bottle()

xray_recorder.configure(service='fallback_name', dynamic_naming='*mysite.com*')
app.install(XRayMiddleware(xray_recorder))

使用 X-Ray 支持Flask、Django 和 Bottle的无服务器

无服务器是一种应用程序模型,它使您可以将更多操作责任转移到 AWS。因此,您可以只关注您的应用程序和服务,而不是基础设施管理任务,例如服务器配置、修补、操作系统维护和容量配置。使用无服务器,您可以将 Web 应用程序部署到 AWS Lambda,并让客户通过 Lambda 调用端点与之交互,例如 Amazon API Gateway

X-Ray原生支持无服务器模型,无需额外配置。在Lambda中,当达到端点时,中间件生成的是Subsegments而不是Segments。这是因为Segments无法在Lambda函数内部生成,而是由Lambda容器自动生成。因此,在使用此模型中的中间件时,确保您的方法只生成Subsegments非常重要。

以下指南展示了如何设置一个利用API Gateway和Lambda的无服务器应用程序的示例。

在无服务器环境中对Web框架进行性能监控

与aiohttp一起工作

添加aiohttp中间件。支持aiohttp >= 2.3。

from aiohttp import web

from aws_xray_sdk.ext.aiohttp.middleware import middleware
from aws_xray_sdk.core import xray_recorder
from aws_xray_sdk.core.async_context import AsyncContext

xray_recorder.configure(service='fallback_name', context=AsyncContext())

app = web.Application(middlewares=[middleware])
app.router.add_get("/", handler)

web.run_app(app)

跟踪aiohttp客户端。支持aiohttp >= 3。

from aws_xray_sdk.ext.aiohttp.client import aws_xray_trace_config

async def foo():
    trace_config = aws_xray_trace_config()
    async with ClientSession(loop=loop, trace_configs=[trace_config]) as session:
        async with session.get(url) as resp
            await resp.read()

使用SQLAlchemy ORM

SQLAlchemy集成要求您覆盖SQLAlchemy的Session和Query类

SQLAlchemy集成使用子段,因此您在查询之前需要启动一个段。

from aws_xray_sdk.core import xray_recorder
from aws_xray_sdk.ext.sqlalchemy.query import XRaySessionMaker

xray_recorder.begin_segment('SQLAlchemyTest')

Session = XRaySessionMaker(bind=engine)
session = Session()

xray_recorder.end_segment()
app = Flask(__name__)

xray_recorder.configure(service='fallback_name', dynamic_naming='*mysite.com*')
XRayMiddleware(app, xray_recorder)

添加Flask-SQLAlchemy

from aws_xray_sdk.core import xray_recorder
from aws_xray_sdk.ext.flask.middleware import XRayMiddleware
from aws_xray_sdk.ext.flask_sqlalchemy.query import XRayFlaskSqlAlchemy

app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///:memory:"

XRayMiddleware(app, xray_recorder)
db = XRayFlaskSqlAlchemy(app)

忽略httplib请求

如果您想忽略某些httplib请求,可以根据正在请求的主机名或URL进行操作。主机名匹配使用Python fnmatch库,该库使用Unix glob样式匹配。

from aws_xray_sdk.ext.httplib import add_ignored as xray_add_ignored

# ignore requests to test.myapp.com
xray_add_ignored(hostname='test.myapp.com')

# ignore requests to a subdomain of myapp.com with a glob pattern
xray_add_ignored(hostname='*.myapp.com')

# ignore requests to /test-url and /other-test-url
xray_add_ignored(urls=['/test-path', '/other-test-path'])

# ignore requests to myapp.com for /test-url
xray_add_ignored(hostname='myapp.com', urls=['/test-url'])

如果您使用httplib的子类来发送请求,还可以根据发起请求的类名进行过滤。这必须使用完整的包名来进行匹配。

from aws_xray_sdk.ext.httplib import add_ignored as xray_add_ignored

# ignore all requests made by botocore
xray_add_ignored(subclass='botocore.awsrequest.AWSHTTPConnection')

许可证

Python的AWS X-Ray SDK采用Apache 2.0许可证。有关更多信息,请参阅LICENSE和NOTICE.txt文件。

项目详情


下载文件

下载适用于您平台的文件。如果您不确定该选择哪个,请了解更多关于安装包的信息。

源分布

aws_xray_sdk-2.14.0.tar.gz (94.0 kB 查看哈希)

上传时间

构建分布

aws_xray_sdk-2.14.0-py2.py3-none-any.whl (101.9 kB 查看哈希)

上传时间 Python 2 Python 3

支持者