наблюдаемость: завершить базовый контур Community
CI / Rust Checks (push) Failing after 4m28s
CI / UI Checks (push) Has been skipped
CI / Frontend E2E (push) Has been skipped
CI / Community Image Smoke (push) Has been skipped
CI / Deploy (push) Has been skipped

Добавить структурированные журналы, метрики, трассировку и безопасный канал критических ошибок. Усилить границы рантайма, тесты, проверку зависимостей и сценарии развёртывания.
This commit is contained in:
2026-07-31 01:01:14 +03:00
parent 99bd05c145
commit 0e8f1ca03a
160 changed files with 13506 additions and 1499 deletions
@@ -38,7 +38,8 @@ use sha2::{Digest, Sha256};
use time::{OffsetDateTime, format_description::well_known::Rfc3339};
use tokio::net::TcpListener;
use tokio::time::sleep;
use tracing_subscriber::{filter::LevelFilter, fmt::MakeWriter, prelude::*};
use tracing_subscriber::fmt::MakeWriter;
use uuid::Version;
use crank_community_mcp::{
auth::{CommunityMachineCredentialVerifier, SharedMachineCredentialVerifier},
@@ -46,6 +47,9 @@ use crank_community_mcp::{
catalog::PublishedToolCatalog,
session::{InMemorySessionStore, SharedSessionStore, TransportSessionStore},
};
use crank_observability::{
ObservabilityConfig, RedactionLimits, ServiceIdentity, build_subscriber,
};
fn test_workspace_id() -> WorkspaceId {
WorkspaceId::new("ws_default")
@@ -404,7 +408,10 @@ async fn generates_request_id_for_tool_call_responses_and_logs() {
.to_str()
.unwrap()
.to_owned();
assert!(!request_id.is_empty());
assert_eq!(
uuid::Uuid::parse_str(&request_id).unwrap().get_version(),
Some(Version::SortRand)
);
let call_result = response.json::<Value>().await.unwrap();
assert_eq!(call_result["result"]["isError"], false);
@@ -427,7 +434,7 @@ async fn generates_request_id_for_tool_call_responses_and_logs() {
assert_eq!(logs[0].log.request_id.as_deref(), Some(request_id.as_str()));
}
#[tokio::test]
#[tokio::test(flavor = "current_thread")]
async fn emits_request_id_in_mcp_ingress_logs() {
let registry = test_registry().await;
let upstream_base_url = spawn_upstream_server().await;
@@ -456,6 +463,18 @@ async fn emits_request_id_in_mcp_ingress_logs() {
)
.await;
let writer = SharedLogWriter::default();
let subscriber = build_subscriber(
ObservabilityConfig::new(
ServiceIdentity::try_new("mcp-server", "test", "test").unwrap(),
"info",
RedactionLimits::default(),
),
writer.clone(),
)
.unwrap();
let dispatch = tracing::Dispatch::new(subscriber);
let _guard = tracing::dispatcher::set_default(&dispatch);
let base_url = spawn_mcp_server(build_test_app(
registry,
Duration::from_millis(0),
@@ -464,18 +483,7 @@ async fn emits_request_id_in_mcp_ingress_logs() {
.await;
let client = reqwest::Client::new();
let mcp_url = agent_mcp_url(&base_url, "sales-request-trace");
let writer = SharedLogWriter::default();
let subscriber = tracing_subscriber::registry().with(
tracing_subscriber::fmt::layer()
.with_writer(writer.clone())
.without_time()
.with_ansi(false)
.with_target(false)
.compact()
.with_filter(LevelFilter::INFO),
);
let _ = tracing::subscriber::set_global_default(subscriber);
let response = post_jsonrpc_response(
&client,
&mcp_url,
@@ -500,14 +508,16 @@ async fn emits_request_id_in_mcp_ingress_logs() {
assert_eq!(response.status(), reqwest::StatusCode::OK);
let logs = writer.output();
assert!(
logs.contains("mcp request received"),
"captured logs did not include ingress marker: {logs}"
);
assert!(logs.contains("req_mcp_trace_123"));
assert!(logs.contains("sales-request-trace"));
assert!(logs.contains("default"));
assert!(logs.contains("initialize"));
let event = logs
.lines()
.filter_map(|line| serde_json::from_str::<Value>(line).ok())
.find(|event| event["event"] == "mcp.request.received")
.unwrap();
assert_eq!(event["service"], "mcp-server");
assert_eq!(event["request_id"], "req_mcp_trace_123");
assert_eq!(event["fields"]["agent_slug"], "sales-request-trace");
assert_eq!(event["fields"]["workspace_slug"], "default");
assert_eq!(event["fields"]["jsonrpc_method"], "initialize");
}
#[tokio::test]
@@ -803,11 +813,30 @@ async fn get_requires_session_header() {
.get(agent_mcp_url(&base_url, "sales-get-sse-missing"))
.header(header::ACCEPT, "text/event-stream")
.header(header::AUTHORIZATION, format!("Bearer {api_key}"))
.header("x-request-id", "req_early_mcp_error")
.send()
.await
.unwrap();
assert_eq!(response.status(), reqwest::StatusCode::BAD_REQUEST);
assert_eq!(
response.headers()["x-request-id"].to_str().unwrap(),
"req_early_mcp_error"
);
let invalid_response = client
.get(agent_mcp_url(&base_url, "sales-get-sse-missing"))
.header(header::ACCEPT, "text/event-stream")
.header(header::AUTHORIZATION, format!("Bearer {api_key}"))
.header("x-request-id", "bad,value")
.send()
.await
.unwrap();
let generated = invalid_response.headers()["x-request-id"].to_str().unwrap();
assert_eq!(
uuid::Uuid::parse_str(generated).unwrap().get_version(),
Some(Version::SortRand)
);
}
#[tokio::test]