İçeriğe geç
mcpd
daemon yok
Kaynak

OpenTelemetry

Ajanınız zaten OpenTelemetry yayıyorsa, mcpd bir endpoint değişikliğinden ibarettir. Bu sayfa OTLP yolunun tamamıdır: üç endpoint, kodlama ve mcpd'nin okuduğu her öznitelik.

Üç endpoint

mcpd, OTLP HTTP endpoint'lerini sorgu API'si ve arayüzüyle aynı porttan sunar. Önüne konacak bir collector, ikinci bir konteyner ve ayrı bir alıcı portu yoktur.

Endpoint Kabul ettiği Yanıtladığı
POST /v1/traces ExportTraceServiceRequest partialSuccess.rejectedSpans
POST /v1/logs ExportLogsServiceRequest partialSuccess.rejectedLogRecords
POST /v1/metrics ExportMetricsServiceRequest partialSuccess.rejectedDataPoints

Başarılı her dışa aktarım, OTLP'nin bir sayı taşıyan kendi partialSuccess biçimiyle yanıtlanır. Bir collector'ın gönderene bir şey düşürdüğünü söyleme yolu budur ve exporter'lar bunu okur. Boş bir gövde döndürmek, gönderenin almadığı bir başarıyı bildirmesine yol açardı.

Bir exporter'ı buraya yöneltmek

İşi iki değişken görür. Bunları ajanınızı çalıştıran sürecin ortamında ayarlayın, başka hiçbir şey değişmez.

exporter

# Taban adres. /v1/traces yolunu exporter'ın kendisi ekler.
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317
export OTEL_EXPORTER_OTLP_PROTOCOL=http/json

# İsteğe bağlı. Payload'larınız büyükse gzip gönderin.
export OTEL_EXPORTER_OTLP_COMPRESSION=gzip

# Yalnızca mcpd --ingest-key ile çalışıyorsa.
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer YOUR_INGEST_KEY"

Bir sessizliğin nedenini aramadan önce bilinmeye değer iki ayrıntı var. Birincisi, OTEL_EXPORTER_OTLP_ENDPOINT bir taban adrestir ve exporter sinyal yolunu onun sonuna kendisi ekler. Yolu da içeren tam adresi vermek isterseniz bunun yerine OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ayarlayın. İkincisi, OpenTelemetry'de 4317 portu alışılageldiği üzere gRPC portudur, 4318 ise HTTP portudur. mcpd her şeyi tek porttan sunduğu için HTTP'yi 4317'den sunar; yani varsayılan portunda bırakılmış bir exporter 4318'e gönderir ve siz hiçbir şeyin geldiğini görmezsiniz. Portu açıkça yazın.

Trace'ler için her iki kodlama

/v1/traces, content-type başlığını okur ve iki kodlamayı da kabul eder: içinde protobuf geçiyorsa OTLP/protobuf, geçmiyorsa OTLP/JSON. OpenTelemetry'nin varsayılanı protobuf'tur, yani mcpd'ye yöneltilmiş, değiştirilmemiş bir SDK'nın gönderdiği trace'ler hiçbir yapılandırma olmadan yerine ulaşır.

/v1/logs ve /v1/metrics yalnızca JSON kabul eder. Oraya gelen bir protobuf gövdesi body is not valid JSON diyerek geri çevrilir. Üç sinyali de gönderiyorsanız protokolü bir kez, genel olarak ayarlayın:

her sinyal için json

export OTEL_EXPORTER_OTLP_PROTOCOL=http/json

Hiç content-type gönderilmediğinde mcpd application/json varsayar.

Sıkıştırma ve boyut

Bir istek gövdesi content-encoding: gzip ile, identity ile ya da hiç kodlama başlığı olmadan gelebilir. Başka her şey adıyla geri çevrilir: content-encoding "br" is not supported; use gzip or send the body uncompressed. Yanıtlar içerik pazarlığıyla sıkıştırılır, yani yavaş bir hat üzerinden geri okunan büyük bir trace de sıkıştırılır.

Tek bir isteğe iki sınır uygulanır. Gövde sınırı 32 MiB; gelen şeyin üzerinden ölçülür, yani gzip size yer kazandırır. Yığın sınırı 10.000 sinyaldir ve her alım kapısında kod çözüldükten sonra sayılır: /v1/traces üzerinde span'ler, /v1/logs üzerinde kayıtlar, /v1/metrics üzerinde veri noktaları ve /v1/ingest üzerinde istekteki her şey. Daha büyük bir yığın, iki sayıyı da adlandıran 413 payload_too_large ile geri çevrilir. İki sınır da birer ayardır: Yapılandırma sayfasında anlatılan --max-body-bytes ve --max-batch-signals.

Gelmekle saklanmak arasında ne olur

Bir OTLP span'i ile yerel bir span aynı yoldan geçer. Hattın ortak olmasının amacı budur: aşağıdaki sıra iki kapı arasında ayrışamaz.

Ingest pipeline
  1. Decode

    OTLP or native, gzip or plain

  2. Sample

    Decided once, at the root

  3. Redact

    Before anything is written

  4. Price

    From the configured price book

  5. Store

    One transaction per batch

Redaction is stage three, not a cleanup job. A value that a rule matches never reaches storage at all.

Bir OTLP span'inin maliyet rakamı almasının sebebi, maliyetin alım anında hesaplanmasıdır. mcpd, span geldiği anda bu sunucunun çalıştığı fiyat listesine göre onu fiyatlandırır; böylece oranlarınızı sonradan değiştirmeniz geçen ayın maliyetini sessizce yeniden yazamaz. Bakınız Maliyet muhasebesi.

Her iki semantik kural kümesi

Yapay zekâ span'leri için birbiriyle yarışan iki öznitelik adı kümesi kullanılıyor: OpenTelemetry'nin kendi gen_ai.* adları ve OpenInference'ın openinference.span.kind ile birlikte gelen llm.* adları. mcpd ikisini de okur, üstüne kendi mcpd.* adlarını da. Hiçbir şeyi yeniden adlandırmazsınız.

Aşağıdaki her satır sırayla okunur, ilk eşleşen kazanır. Hiçbir satırın adlandırmadığı bir öznitelik yine de saklanır: düzleştirilmiş öznitelik haritasının tamamı span'in üzerinde durur, yani gönderdiğiniz hiçbir şey eşlenmediği için kaybolmaz.

Model, payload ve kullanım

mcpd alanı Sırayla şuradan okunur
model gen_ai.request.model, gen_ai.response.model, llm.model_name, mcpd.model
provider gen_ai.system, llm.provider, mcpd.provider
input input.value, gen_ai.prompt, mcpd.input
output output.value, gen_ai.completion, mcpd.output
entity_name gen_ai.agent.name, mcpd.entity.name
usage.input_tokens gen_ai.usage.input_tokens, gen_ai.usage.prompt_tokens, llm.token_count.prompt, mcpd.usage.input_tokens
usage.output_tokens gen_ai.usage.output_tokens, gen_ai.usage.completion_tokens, llm.token_count.completion, mcpd.usage.output_tokens
usage.total_tokens llm.token_count.total, gen_ai.usage.total_tokens
input_details.cache_read gen_ai.usage.cache_read_input_tokens, llm.token_count.prompt_details.cache_read, mcpd.usage.cache_read_tokens
input_details.cache_write gen_ai.usage.cache_creation_input_tokens, llm.token_count.prompt_details.cache_write, mcpd.usage.cache_write_tokens
input_details.audio llm.token_count.prompt_details.audio
output_details.reasoning llm.token_count.completion_details.reasoning, gen_ai.usage.reasoning_tokens
output_details.audio llm.token_count.completion_details.audio

Üç token sayısından hiçbirini taşımayan bir span, sıfırlarla dolu bir kullanım nesnesi yerine hiç kullanım nesnesi taşımaz. Sıfır girdi token'ı ile bilinmeyen girdi token'ı farklı olgulardır ve ikincisi kastedilirken birincisine dayanılarak kurulmuş bir maliyet raporu, kimsenin fark etmeyeceği bir biçimde yanlıştır.

İlişkilendirme

İlişkilendirme alanları, tek bir kullanıcının ya da tek bir oturumun çalıştırmalarını istemenizi sağlayan şeydir. Önce span öznitelikleri, sonra kaynak öznitelikleri okunur.

mcpd alanı Sırayla şuradan okunur
project span üzerindeki mcpd.project, sonra kaynak üzerindeki, sonra daemon'ın --project değeri
environment mcpd.environment, kaynak deployment.environment.name, kaynak deployment.environment
service_name kaynak service.name
service_version kaynak service.version
session_id gen_ai.conversation.id, session.id, mcpd.session_id
thread_id mcpd.thread_id, thread.id
user_id user.id, enduser.id, mcpd.user_id
request_id mcpd.request_id, http.request.id
release mcpd.release, kaynak service.version
run_id, resource_id, experiment_id mcpd.run_id, mcpd.resource_id, mcpd.experiment_id
tags dize dizisi olarak mcpd.tags

Durum ve hatalar

OTLP durum kodu 1 ise ok, 2 ise error olur. Bitiş zamanı olan ve durumu ayarlanmamış bir span ok olarak kaydedilir, çünkü şikâyet etmeden biten bir span başarılı olmuştur. Bitiş zamanı olmayan ve durumu ayarlanmamış bir span unset kalır: span hâlâ çalışıyordur ve mcpd bir sonuç uydurmak yerine onu böyle saklar.

Hatalı bir span'de mesaj önce status.message, sonra exception.message alanından gelir; ikisi de yoksa unspecified error dizesi yazılır. Hata türü exception.type alanından, yığın izi exception.stacktrace alanından gelir. Hatalı bir span her zaman bir mesaj taşır, çünkü metni olmayan bir "bir şey başarısız oldu" ile yapabileceğiniz bir şey yoktur.

Span türü

Tür, bir span'in şelalede nasıl çizileceğini belirler. mcpd bunu özgüllük sırasına göre çıkarır ve her zaman güvenli olan generic değerine düşer. Bir span'i yanlış etiketlemek, hiç etiketlememekten kötüdür.

  1. mcpd'nin bildiği bir türü adlandırdığında mcpd.span.kind.
  2. openinference.span.kind.
  3. gen_ai.operation.name.
  4. Yalnızca tek bir span türünün taşıdığı bir özniteliğin varlığı.
Öznitelik değeri mcpd türü
openinference.span.kind=LLMmodel_generation
openinference.span.kind=CHAINworkflow_run
openinference.span.kind=TOOLtool_call
openinference.span.kind=AGENTagent_run
openinference.span.kind=RETRIEVERretrieval
openinference.span.kind=EMBEDDINGrag_embedding
openinference.span.kind=RERANKERrag_action
openinference.span.kind=GUARDRAILguardrail
openinference.span.kind=EVALUATORscorer_run
gen_ai.operation.name=chatmodel_generation
gen_ai.operation.name=text_completionmodel_generation
gen_ai.operation.name=generate_contentmodel_generation
gen_ai.operation.name=embeddingsrag_embedding
gen_ai.operation.name=execute_tooltool_call
gen_ai.operation.name=invoke_agentagent_run
gen_ai.operation.name=create_agentagent_run
gen_ai.system, llm.model_name, llm.provider özniteliklerinden herhangi biri varsamodel_generation
mcp.tool.name varsamcp_tool_call
http.request.method ya da http.method varsahttp_request
başka her şeygeneric

openinference.span.kind ya da gen_ai.operation.name altında mcpd'nin tanımadığı bir span türü, geri çevrilmek yerine generic değerine düşer. Türlerin tam listesi veri modelinde bulunur.

Loglar ve metrikler

Log kayıtları, spesifikasyonun öngördüğü gibi önem derecesi numarasına göre eşlenir: 1 ile 4 arası trace, 5 ile 8 arası debug, 9 ile 12 arası info, 13 ile 16 arası warn, 17 ile 20 arası error ve bunun üstündeki her şey fatal. Önem derecesi numarası olmayan bir kayıt info sayılır. Mesaj body.stringValue alanından, logger adı scope adından gelir; traceId ve spanId geçerli oldukları sürece saklanır, ki bir log satırını onu yayan span'in yanına koyan şey budur.

Metriklerde sum'lar counter, gauge'ler gauge olur. Histogramlar toplamları ve sayılarıyla, bucket sınırları korunarak kaydedilir: mcpd, önceden toplanmış bir histogramdan kesin bir kuantili yeniden türetebiliyormuş gibi yapmaz. Exemplar'lar saklanır, ki bir grafikteki sıçramadan onu doğuran çalıştırmayı açmanızı sağlayan şey budur. Çoğu araç bunları atar.

Id'ler ve W3C traceparent

mcpd, OpenTelemetry'nin tanımlayıcı biçimlerini birebir kullanır: trace id 128 bittir ve 32 küçük harfli onaltılık karakterle, span id 64 bittir ve 16 karakterle yazılır. Çeviri katmanını ortadan kaldıran şey, tel biçiminin aynı tutulmasıdır. Tümü sıfır olan id, "trace yok" anlamına ayrılmıştır ve mcpd'nin kendi ürettiği id'ler de dahil olmak üzere geçtiği her yerde geri çevrilir.

OTLP/JSON, id alanları için onaltılık öngörür, ama birkaç SDK base64 yayar. mcpd ikisini de kabul eder ve onaltılık saklar. Id'leri eksik, yanlış uzunlukta ya da tümü sıfır olan bir span atlanır ve yığının geri kalanı yine de yazılır; çünkü bir tane kötü span yüzünden on bin iyi span'i geri çeviren bir collector, insanların kapattığı bir collector'dır.

Zaman damgaları, Unix epoch'undan bu yana geçen nanosaniyelerdir. 253 değerini aştıkları için OTLP/JSON onları dize olarak gönderir ve mcpd de dize olarak ayrıştırır. Kayan noktalı sayı olarak okumak duyarlılık kaybettirir; bu da aslında öyle olmadığı hâlde birbirinden mikrosaniyelerle ayrılmış gibi görünen span'ler olarak ortaya çıkar. 0 olan ya da hiç bulunmayan bir endTimeUnixNano, span'in bitmediği anlamına gelir.

Bir traceparent başlığı version-traceid-parentid-flags biçimindedir. mcpd bunu spesifikasyonun koyduğu kurallarla ayrıştırır: ff sürümü geri çevrilir, 00 sürümünde tam olarak dört alan bulunmalıdır, sonraki sürümler daha fazlasını taşıyabilir, id'ler doğrulanmalıdır ve bayrak baytının 0. biti örneklenmiş bayrağıdır. Bozuk bir başlık hiçbir zaman bir isteği geri çevirme nedeni değildir. mcpd onun yerine yeni bir trace başlatır.

Bunun önemli olduğu yer: mcpd SDK'ları gelen bir traceparent başlığını okur ve giden çağrılarda bir tane yayar, böylece bir trace servis sınırından sağ çıkar. OTLP endpoint'leri id'lerini payload'dan alır, çünkü exporter'ınız onları zaten span'lerin içine koymuştur. Bir trace, mcpd ile ölçümlemediğiniz bir serviste başlıyorsa onun traceparent başlığını iletin; iki yarı da tek bir trace id altında yerine ulaşsın.

Bir istek, eksiksiz

Yukarıdakilerin hiçbiri SDK istemez. Bu, bir terminale yapıştırabileceğiniz eksiksiz ve geçerli bir dışa aktarımdır:

ham OTLP/JSON

curl -X POST http://localhost:4317/v1/traces \
  -H 'content-type: application/json' \
  -d '{
  "resourceSpans": [{
    "resource": { "attributes": [
      { "key": "service.name", "value": { "stringValue": "checkout-agent" } }
    ]},
    "scopeSpans": [{
      "spans": [{
        "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
        "spanId": "00f067aa0ba902b7",
        "name": "chat gpt-4o",
        "startTimeUnixNano": "1700000000000000000",
        "endTimeUnixNano": "1700000001500000000",
        "status": { "code": 1 },
        "attributes": [
          { "key": "gen_ai.system", "value": { "stringValue": "openai" } },
          { "key": "gen_ai.request.model", "value": { "stringValue": "gpt-4o" } },
          { "key": "gen_ai.operation.name", "value": { "stringValue": "chat" } },
          { "key": "gen_ai.usage.input_tokens", "value": { "intValue": "1200" } },
          { "key": "gen_ai.usage.output_tokens", "value": { "intValue": "350" } }
        ]
      }]
    }]
  }]
}'

# {"partialSuccess":{"rejectedSpans":0,"errorMessage":""}}

OTLP'nin taşıyamadıkları

OTLP'nin span, log ve metrik için bir biçimi vardır. Bir makine puanı, bir insanın başparmak aşağısı ya da bir yön notu için hiçbir biçimi, modern bir sağlayıcının fatura kestiği token ayrıntısı için de hiçbir sözcük dağarcığı yoktur. Bunları göndermenin iki yolu var:

  • Veri modelinin tamamını tek bir istekte taşıyan, mcpd'nin yerel yığın uç noktası POST /v1/ingest.
  • OTLP üzerinden zaten gönderdiğiniz bir trace'e iliştirilen POST /v1/api/scores ve POST /v1/api/feedback.

İkisini karıştırmak olağandır ve beklenir. Span'leri zaten çalıştırdığınız OpenTelemetry SDK'sıyla dışa aktarın, puanları da değerlendirme işinizden gönderin. Trace id üzerinden birleşirler. Bakınız Puanlar ve geri bildirim ve HTTP API.

Portu açmadan önce

--ingest-key ayarlanmamışsa 4317'ye erişebilen herkes oraya yazabilir; --read-key ayarlanmamışsa saklanan her prompt'u okuyabilir. mcpd, ikisinden biri açık bırakılmışken loopback dışı bir adrese bağlandığında başlangıçta bir uyarı loglar. Bunları yapılandırmayla ayarlayın, sonra anahtarı Authorization: Bearer olarak gönderin; yukarıdaki OTEL_EXPORTER_OTLP_HEADERS tam da bunu yapar.

anahtarlarla çalıştır

mcpd --ingest-key $INGEST_KEY --read-key $READ_KEY