fastapi integra elastic-apm para implementar monitoramento de desempenho
Este artigo se aplica ao Starlette/FastAPI
Plano de fundo da versão do software:
elástico 8,9
horas 6.x
O texto oficial é o seguinte:
Suporte Starlette/FastAPI
Incorporar o Elastic APM ao seu projeto Starlette requer apenas algumas etapas fáceis.
Instalação
Instale o agente Elastic APM usando pip:
$ pip install elastic-apm
ou adicione elastic-apm
ao arquivo do seu projeto requirements.txt
.
Configurar
Para configurar o agente, é necessário inicializá-lo com as configurações apropriadas.
As configurações são definidas por meio de variáveis de ambiente ou como argumentos de inicialização.
Você pode encontrar uma lista de todas as configurações disponíveis na página Configuração .
Para inicializar o agente para sua aplicação usando variáveis de ambiente, adicione o middleware ElasticAPM à sua aplicação Starlette:
from starlette.applications import Starlette
from elasticapm.contrib.starlette import ElasticAPM
app = Starlette()
app.add_middleware(ElasticAPM)
Aviso | Se você estiver usando qualquer BaseHTTPMiddleware middleware, deverá adicioná-lo antes do middleware ElasticAPM. Isso ocorre porque BaseHTTPMiddleware interrompe contextvar a propagação, conforme observado aqui . |
---|
Para configurar o agente usando argumentos de inicialização:
from starlette.applications import Starlette
from elasticapm.contrib.starlette import make_apm_client, ElasticAPM
apm = make_apm_client({
'SERVICE_NAME': '<SERVICE-NAME>',
'SECRET_TOKEN': '<SECRET-TOKEN>',
})
app = Starlette()
app.add_middleware(ElasticAPM, client=apm)
API rápida
Como FastAPI oferece suporte ao middleware Starlette, usar o agente com FastAPI é quase exatamente o mesmo que usar Starlette:
from fastapi import FastAPI
from elasticapm.contrib.starlette ElasticAPM
app = FastAPI()
app.add_middleware(ElasticAPM)
Uso
Depois de configurar o agente, ele rastreará automaticamente as transações e capturará exceções não detectadas no starlette.
Capture uma exceção arbitrária chamando capture_exception
:
try:
1 / 0
except ZeroDivisionError:
apm.client.capture_exception()
Registre uma mensagem genérica com capture_message
:
apm.client.capture_message('hello, world!')
Métricas de desempenho
Se você seguiu as instruções acima, o agente instalou nosso middleware de instrumentação que processará todas as solicitações por meio do seu aplicativo. Isso medirá os tempos de resposta, bem como dados detalhados de desempenho para todas as tecnologias suportadas.
Observação | Devido ao fato de que asyncio os drivers geralmente são separados de seus equivalentes síncronos, é necessária instrumentação específica para todos os drivers. O suporte para drivers assíncronos é atualmente bastante limitado. |
---|
Ignorando rotas específicas
Você pode usar a TRANSACTIONS_IGNORE_PATTERNS
opção de configuração para ignorar rotas específicas. A lista fornecida deve ser uma lista de expressões regulares que correspondem ao nome da transação:
apm = make_apm_client({
# ...
'TRANSACTIONS_IGNORE_PATTERNS': ['^GET /secret', '/extra_secret']
# ...
})
Isso ignoraria quaisquer solicitações usando a GET /secret
rota e quaisquer solicitações contendo /extra_secret
.
Versões Starlette e Python suportadas
Uma lista de versões Starlette e Python suportadas pode ser encontrada em nossa página de Tecnologias Suportadas .
Observação | O Elastic APM é compatível apenas asyncio com Python 3.7+ |
---|
Exemplos de uso específicos
Depois de adicionar a configuração do código acima, você pode ver o monitoramento do serviço correspondente na interface apm do kibana seguindo as etapas para iniciar o aplicativo normalmente.
Em relação ao arquivo de configuração, você pode consultar a classe Config no arquivo venv/lib/python3.7/site-packages/elasticapm/conf/ init.py no pacote elastic-apm . Os campos em letras maiúsculas são a configuração Unid.
class Config(_ConfigBase):
service_name = _ConfigValue(
"SERVICE_NAME",
validators=[RegexValidator("^[a-zA-Z0-9 _-]+$")],
default="unknown-python-service",
required=True,
)
service_node_name = _ConfigValue("SERVICE_NODE_NAME")
environment = _ConfigValue("ENVIRONMENT")
transport_json_serializer = _ConfigValue("TRANSPORT_JSON_SERIALIZER")
secret_token = _ConfigValue("SECRET_TOKEN")
api_key = _ConfigValue("API_KEY")
debug = _BoolConfigValue("DEBUG", default=False)
server_url = _ConfigValue("SERVER_URL", default="http://127.0.0.1:8200", required=True)
server_cert = _ConfigValue("SERVER_CERT", validators=[FileIsReadableValidator()])
server_ca_cert_file = _ConfigValue("SERVER_CA_CERT_FILE", validators=[FileIsReadableValidator()])
verify_server_cert = _BoolConfigValue("VERIFY_SERVER_CERT", default=True)
use_certifi = _BoolConfigValue("USE_CERTIFI", default=True)
include_paths = _ListConfigValue("INCLUDE_PATHS")
exclude_paths = _ListConfigValue("EXCLUDE_PATHS", default=compat.get_default_library_patters())
filter_exception_types = _ListConfigValue("FILTER_EXCEPTION_TYPES")
server_timeout = _ConfigValue(
"SERVER_TIMEOUT",
type=float,
validators=[
UnitValidator(r"^((?:-)?\d+)(ms|s|m)?$", r"\d+(ms|s|m)", {
"ms": 0.001, "s": 1, "m": 60, None: 1000})
],
default=5,
)
hostname = _ConfigValue("HOSTNAME", default=socket.gethostname())
auto_log_stacks = _BoolConfigValue("AUTO_LOG_STACKS", default=True)
transport_class = _ConfigValue("TRANSPORT_CLASS", default="elasticapm.transport.http.Transport", required=True)
processors = _ListConfigValue(
"PROCESSORS",
default=[
"elasticapm.processors.sanitize_stacktrace_locals",
"elasticapm.processors.sanitize_http_request_cookies",
"elasticapm.processors.sanitize_http_response_cookies",
"elasticapm.processors.sanitize_http_headers",
"elasticapm.processors.sanitize_http_wsgi_env",
"elasticapm.processors.sanitize_http_request_body",
],
)
sanitize_field_names = _ListConfigValue(
"SANITIZE_FIELD_NAMES", type=starmatch_to_regex, default=BASE_SANITIZE_FIELD_NAMES
)
metrics_sets = _ListConfigValue(
"METRICS_SETS",
default=[
"elasticapm.metrics.sets.cpu.CPUMetricSet",
],
)
metrics_interval = _DurationConfigValue(
"METRICS_INTERVAL",
validators=[ExcludeRangeValidator(0.001, 0.999, "{range_start} - {range_end} s")],
default=timedelta(seconds=30),
)
breakdown_metrics = _BoolConfigValue("BREAKDOWN_METRICS", default=True)
prometheus_metrics = _class Config(_ConfigBase):
service_name = _ConfigValue(
"SERVICE_NAME",
validators=[RegexValidator("^[a-zA-Z0-9 _-]+$")],
default="unknown-python-service",
required=True,
)
service_node_name = _ConfigValue("SERVICE_NODE_NAME")
environment = _ConfigValue("ENVIRONMENT")
transport_json_serializer = _ConfigValue("TRANSPORT_JSON_SERIALIZER")
secret_token = _ConfigValue("SECRET_TOKEN")
api_key = _ConfigValue("API_KEY")
debug = _BoolConfigValue("DEBUG", default=False)
server_url = _ConfigValue("SERVER_URL", default="http://127.0.0.1:8200", required=True)
server_cert = _ConfigValue("SERVER_CERT", validators=[FileIsReadableValidator()])
server_ca_cert_file = _ConfigValue("SERVER_CA_CERT_FILE", validators=[FileIsReadableValidator()])
verify_server_cert = _BoolConfigValue("VERIFY_SERVER_CERT", default=True)
use_certifi = _BoolConfigValue("USE_CERTIFI", default=True)
include_paths = _ListConfigValue("INCLUDE_PATHS")
exclude_paths = _ListConfigValue("EXCLUDE_PATHS", default=compat.get_default_library_patters())
filter_exception_types = _ListConfigValue("FILTER_EXCEPTION_TYPES")
server_timeout = _ConfigValue(
"SERVER_TIMEOUT",
type=float,
validators=[
UnitValidator(r"^((?:-)?\d+)(ms|s|m)?$", r"\d+(ms|s|m)", {
"ms": 0.001, "s": 1, "m": 60, None: 1000})
],
default=5,
)
hostname = _ConfigValue("HOSTNAME", default=socket.gethostname())
auto_log_stacks = _BoolConfigValue("AUTO_LOG_STACKS", default=True)
transport_class = _ConfigValue("TRANSPORT_CLASS", default="elasticapm.transport.http.Transport", required=True)
processors = _ListConfigValue(
"PROCESSORS",
default=[
"elasticapm.processors.sanitize_stacktrace_locals",
"elasticapm.processors.sanitize_http_request_cookies",
"elasticapm.processors.sanitize_http_response_cookies",
"elasticapm.processors.sanitize_http_headers",
"elasticapm.processooolConfigValue("PROMETHEUS_METRICS", default=False)
prometheus_metrics_prefix = _ConfigValue("PROMETHEUS_METRICS_PREFIX", default="prometheus.metrics.")
disable_metrics = _ListConfigValue("DISABLE_METRICS", type=starmatch_to_regex, default=[])
central_config = _BoolConfigValue("CENTRAL_CONFIG", default=True)
api_request_size = _ConfigValue("API_REQUEST_SIZE", type=int, validators=[size_validator], default=768 * 1024)
api_request_time = _DurationConfigValue("API_REQUEST_TIME", default=timedelta(seconds=10))
transaction_sample_rate = _ConfigValue(
"TRANSACTION_SAMPLE_RATE", type=float, validators=[PrecisionValidator(4, 0.0001)], default=1.0
)
transaction_max_spans = _ConfigValue("TRANSACTION_MAX_SPANS", type=int, default=500)
stack_trace_limit = _ConfigValue("STACK_TRACE_LIMIT", type=int, default=50)
span_frames_min_duration = _DurationConfigValue(
"SPAN_FRAMES_MIN_DURATION", default=timedelta(seconds=0.005), unitless_factor=0.001
)
span_stack_trace_min_duration = _DurationConfigValue(
"SPAN_STACK_TRACE_MIN_DURATION", default=timedelta(seconds=0.005), unitless_factor=0.001
)
span_compression_enabled = _BoolConfigValue("SPAN_COMPRESSION_ENABLED", default=True)
span_compression_exact_match_max_duration = _DurationConfigValue(
"SPAN_COMPRESSION_EXACT_MATCH_MAX_DURATION",
default=timedelta(seconds=0.05),
)
span_compression_same_kind_max_duration = _DurationConfigValue(
"SPAN_COMPRESSION_SAME_KIND_MAX_DURATION",
default=timedelta(seconds=0),
)
exit_span_min_duration = _DurationConfigValue(
"EXIT_SPAN_MIN_DURATION",
default=timedelta(seconds=0),
)
collect_local_variables = _ConfigValue("COLLECT_LOCAL_VARIABLES", default="errors")
source_lines_error_app_frames = _ConfigValue("SOURCE_LINES_ERROR_APP_FRAMES", type=int, default=5)
source_lines_error_library_frames = _ConfigValue("SOURCE_LINES_ERROR_LIBRARY_FRAMES", type=int, default=5)
source_lines_span_app_frames = _ConfigValue("SOURCE_LINES_SPAN_APP_FRAMES", type=int, default=0)
source_lines_span_library_frames = _ConfigValue("SOURCE_LINES_SPAN_LIBRARY_FRAMES", type=int, default=0)
local_var_max_length = _ConfigValue("LOCAL_VAR_MAX_LENGTH", type=int, default=200)
local_var_list_max_length = _ConfigValue("LOCAL_VAR_LIST_MAX_LENGTH", type=int, default=10)
local_var_dict_max_length = _ConfigValue("LOCAL_VAR_DICT_MAX_LENGTH", type=int, default=10)
capture_body = _ConfigValue(
"CAPTURE_BODY",
default="off",
validators=[lambda val, _: {"errors": "error", "transactions": "transaction"}.get(val, val)],
)
async_mode = _BoolConfigValue("ASYNC_MODE", default=True)
instrument_django_middleware = _BoolConfigValue("INSTRUMENT_DJANGO_MIDDLEWARE", default=True)
autoinsert_django_middleware = _BoolConfigValue("AUTOINSERT_DJANGO_MIDDLEWARE", default=True)
transactions_ignore_patterns = _ListConfigValue("TRANSACTIONS_IGNORE_PATTERNS", default=[])
transaction_ignore_urls = _ListConfigValue("TRANSACTION_IGNORE_URLS", type=starmatch_to_regex, default=[])
ignore_message_queues = _ListConfigValue("IGNORE_MESSAGE_QUEUES", type=starmatch_to_regex, default=[])
service_version = _ConfigValue("SERVICE_VERSION")
framework_name = _ConfigValue("FRAMEWORK_NAME")
framework_version = _ConfigValue("FRAMEWORK_VERSION")
global_labels = _DictConfigValue("GLOBAL_LABELS")
disable_send = _BoolConfigValue("DISABLE_SEND", default=False)
enabled = _BoolConfigValue("ENABLED", default=True)
recording = _BoolConfigValue("RECORDING", default=True)
instrument = _BoolConfigValue("INSTRUMENT", default=True)
enable_distributed_tracing = _BoolConfigValue("ENABLE_DISTRIBUTED_TRACING", default=True)
capture_headers = _BoolConfigValue("CAPTURE_HEADERS", default=True)
django_transaction_name_from_route = _BoolConfigValue("DJANGO_TRANSACTION_NAME_FROM_ROUTE", default=False)
disable_log_record_factory = _BoolConfigValue("DISABLE_LOG_RECORD_FACTORY", default=False)
use_elastic_traceparent_header = _BoolConfigValue("USE_ELASTIC_TRACEPARENT_HEADER", default=True)
use_elastic_excepthook = _BoolConfigValue("USE_ELASTIC_EXCEPTHOOK", default=False)
cloud_provider = _ConfigValue("CLOUD_PROVIDER", default=True)
log_level = _ConfigValue(
"LOG_LEVEL",
validators=[EnumerationValidator(["trace", "debug", "info", "warning", "warn", "error", "critical", "off"])],
callbacks=[_log_level_callback],
)
log_file = _ConfigValue("LOG_FILE", default="")
log_file_size = _ConfigValue("LOG_FILE_SIZE", validators=[size_validator], type=int, default=50 * 1024 * 1024)
log_ecs_reformatting = _ConfigValue(
"LOG_ECS_REFORMATTING",
validators=[EnumerationValidator(["off", "override"])],
callbacks=[_log_ecs_reformatting_callback],
default="off",
)
trace_continuation_strategy = _ConfigValue(
"TRACE_CONTINUATION_STRATEGY",
validators=[
EnumerationValidator(
[
TRACE_CONTINUATION_STRATEGY.CONTINUE,
TRACE_CONTINUATION_STRATEGY.RESTART,
TRACE_CONTINUATION_STRATEGY.RESTART_EXTERNAL,
]
)
],
default=TRACE_CONTINUATION_STRATEGY.CONTINUE,
)
include_process_args = _BoolConfigValue("INCLUDE_PROCESS_ARGS", default=False)
Introdução aos itens de configuração no site oficial
https://www.elastic.co/guide/en/apm/agent/python/6.x/configuration.html
Introdução ao site oficial do elastic-apm integrando cada framework de linguagem
https://www.elastic.co/guide/en/apm/guide/current/_step_3_install_apm_agents.html