From e2d76fe31870183d1069a6227a93a56b7acb83da Mon Sep 17 00:00:00 2001 From: hamz2a Date: Tue, 26 Nov 2024 16:07:13 +0100 Subject: [PATCH] editoast: log stdcm requests Signed-off-by: hamz2a --- editoast/editoast_models/src/tables.rs | 13 +++++ .../down.sql | 1 + .../up.sql | 6 ++ editoast/openapi.yaml | 56 +++++++++++++++++++ editoast/src/core/conflict_detection.rs | 2 +- editoast/src/core/mod.rs | 1 + editoast/src/core/simulation.rs | 2 +- editoast/src/core/stdcm.rs | 16 ++++-- editoast/src/models/mod.rs | 2 + editoast/src/models/stdcm_log.rs | 23 ++++++++ editoast/src/views/timetable/stdcm.rs | 38 ++++++++++++- 11 files changed, 150 insertions(+), 10 deletions(-) create mode 100644 editoast/migrations/2024-11-21-145205_create_stdcm_logs/down.sql create mode 100644 editoast/migrations/2024-11-21-145205_create_stdcm_logs/up.sql create mode 100644 editoast/src/models/stdcm_log.rs diff --git a/editoast/editoast_models/src/tables.rs b/editoast/editoast_models/src/tables.rs index db0a4992c0d..7c68701cf18 100644 --- a/editoast/editoast_models/src/tables.rs +++ b/editoast/editoast_models/src/tables.rs @@ -596,6 +596,18 @@ diesel::table! { } } +diesel::table! { + use diesel::sql_types::*; + use postgis_diesel::sql_types::*; + + stdcm_logs (id) { + id -> Int8, + trace_id -> Text, + request -> Jsonb, + response -> Jsonb, + } +} + diesel::table! { use diesel::sql_types::*; use postgis_diesel::sql_types::*; @@ -851,6 +863,7 @@ diesel::allow_tables_to_appear_in_same_query!( search_signal, search_study, search_track, + stdcm_logs, stdcm_search_environment, study, temporary_speed_limit, diff --git a/editoast/migrations/2024-11-21-145205_create_stdcm_logs/down.sql b/editoast/migrations/2024-11-21-145205_create_stdcm_logs/down.sql new file mode 100644 index 00000000000..83466c32b52 --- /dev/null +++ b/editoast/migrations/2024-11-21-145205_create_stdcm_logs/down.sql @@ -0,0 +1 @@ +DROP TABLE stdcm_logs; diff --git a/editoast/migrations/2024-11-21-145205_create_stdcm_logs/up.sql b/editoast/migrations/2024-11-21-145205_create_stdcm_logs/up.sql new file mode 100644 index 00000000000..3aaef8e42f3 --- /dev/null +++ b/editoast/migrations/2024-11-21-145205_create_stdcm_logs/up.sql @@ -0,0 +1,6 @@ +CREATE TABLE stdcm_logs ( + id int8 PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY, + trace_id text UNIQUE NOT NULL, + request jsonb NOT NULL, + response jsonb NOT NULL +); diff --git a/editoast/openapi.yaml b/editoast/openapi.yaml index 173ff46f20d..340a86b9679 100644 --- a/editoast/openapi.yaml +++ b/editoast/openapi.yaml @@ -8622,6 +8622,45 @@ components: type: integer format: int64 nullable: true + Response: + oneOf: + - type: object + required: + - simulation + - path + - departure_time + - status + properties: + departure_time: + type: string + format: date-time + path: + $ref: '#/components/schemas/PathfindingResultSuccess' + simulation: + $ref: '#/components/schemas/SimulationResponse' + status: + type: string + enum: + - success + - type: object + required: + - status + properties: + status: + type: string + enum: + - path_not_found + - type: object + required: + - error + - status + properties: + error: + $ref: '#/components/schemas/SimulationResponse' + status: + type: string + enum: + - preprocessing_simulation_error RjsPowerRestrictionRange: type: object description: A range along the train path where a power restriction is applied. @@ -10228,6 +10267,23 @@ components: type: array items: $ref: '#/components/schemas/RangeAllowance' + StdcmLog: + type: object + required: + - id + - trace_id + - request + - response + properties: + id: + type: integer + format: int64 + request: + $ref: '#/components/schemas/Request' + response: + $ref: '#/components/schemas/Response' + trace_id: + type: string StdcmSearchEnvironment: type: object required: diff --git a/editoast/src/core/conflict_detection.rs b/editoast/src/core/conflict_detection.rs index c50fdc4ba10..45689d7f083 100644 --- a/editoast/src/core/conflict_detection.rs +++ b/editoast/src/core/conflict_detection.rs @@ -29,7 +29,7 @@ pub struct ConflictDetectionRequest { pub work_schedules: Option, } -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct TrainRequirements { pub start_time: DateTime, pub spacing_requirements: Vec, diff --git a/editoast/src/core/mod.rs b/editoast/src/core/mod.rs index 48fce5b6cea..680386f71dc 100644 --- a/editoast/src/core/mod.rs +++ b/editoast/src/core/mod.rs @@ -36,6 +36,7 @@ editoast_common::schemas! { simulation::schemas(), pathfinding::schemas(), conflict_detection::schemas(), + stdcm::schemas(), } #[derive(Debug, Clone)] diff --git a/editoast/src/core/simulation.rs b/editoast/src/core/simulation.rs index a9a61ad2811..86a34fedf64 100644 --- a/editoast/src/core/simulation.rs +++ b/editoast/src/core/simulation.rs @@ -34,7 +34,7 @@ editoast_common::schemas! { SimulationResponse, } -#[derive(Debug, Serialize, Derivative)] +#[derive(Debug, Clone, Serialize, Deserialize, Derivative)] #[derivative(Hash)] pub struct PhysicsConsist { pub effort_curves: EffortCurves, diff --git a/editoast/src/core/stdcm.rs b/editoast/src/core/stdcm.rs index 19703288fee..45dbd469fbc 100644 --- a/editoast/src/core/stdcm.rs +++ b/editoast/src/core/stdcm.rs @@ -19,7 +19,11 @@ use super::simulation::SimulationResponse; use crate::core::AsCoreRequest; use crate::core::Json; -#[derive(Debug, Serialize)] +editoast_common::schemas! { + Response, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct Request { /// Infrastructure id pub infra: i64, @@ -61,7 +65,7 @@ pub struct Request { pub temporary_speed_limits: Vec, } -#[derive(Debug, Serialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct PathItem { /// The track offsets of the path item pub locations: Vec, @@ -72,7 +76,7 @@ pub struct PathItem { } /// Contains the data of a step timing, when it is specified -#[derive(Debug, Serialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct StepTimingData { /// Time the train should arrive at this point pub arrival_time: DateTime, @@ -83,7 +87,7 @@ pub struct StepTimingData { } /// Lighter description of a work schedule, with only the relevant information for core -#[derive(Debug, Serialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct WorkSchedule { /// Start time as a time delta from the stdcm start time in ms pub start_time: u64, @@ -94,7 +98,7 @@ pub struct WorkSchedule { } /// Lighter description of a work schedule with only the relevant information for core -#[derive(Debug, Serialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct TemporarySpeedLimit { /// Speed limitation in m/s pub speed_limit: f64, @@ -114,7 +118,7 @@ pub struct UndirectedTrackRange { pub end: u64, } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, ToSchema)] #[serde(tag = "status", rename_all = "snake_case")] // We accepted the difference of memory size taken by variants // Since there is only on success and others are error cases diff --git a/editoast/src/models/mod.rs b/editoast/src/models/mod.rs index f8b1b28148a..28a96bedf55 100644 --- a/editoast/src/models/mod.rs +++ b/editoast/src/models/mod.rs @@ -6,6 +6,7 @@ pub mod fixtures; pub mod infra; pub mod infra_objects; pub mod layers; +pub mod stdcm_log; // We allow unused until models is moved to a separate crate pub mod auth; pub mod pagination; @@ -41,6 +42,7 @@ editoast_common::schemas! { infra::schemas(), projects::schemas(), rolling_stock_model::schemas(), + stdcm_log::schemas(), } #[cfg(test)] diff --git a/editoast/src/models/stdcm_log.rs b/editoast/src/models/stdcm_log.rs new file mode 100644 index 00000000000..7546c7ee17f --- /dev/null +++ b/editoast/src/models/stdcm_log.rs @@ -0,0 +1,23 @@ +use editoast_derive::Model; +use serde::Deserialize; +use serde::Serialize; +use utoipa::ToSchema; + +use crate::core::stdcm::Request; +use crate::core::stdcm::Response; + +editoast_common::schemas! { + StdcmLog, +} + +#[derive(Clone, Debug, Serialize, Deserialize, Model, ToSchema)] +#[model(table = editoast_models::tables::stdcm_logs)] +#[model(gen(ops = cru, list))] +pub struct StdcmLog { + pub id: i64, + pub trace_id: String, + #[model(json)] + pub request: Request, + #[model(json)] + pub response: Response, +} diff --git a/editoast/src/views/timetable/stdcm.rs b/editoast/src/views/timetable/stdcm.rs index a906dc57990..b73e327dba7 100644 --- a/editoast/src/views/timetable/stdcm.rs +++ b/editoast/src/views/timetable/stdcm.rs @@ -17,6 +17,7 @@ use editoast_schemas::train_schedule::Margins; use editoast_schemas::train_schedule::ReceptionSignal; use editoast_schemas::train_schedule::ScheduleItem; use failure_handler::SimulationFailureHandler; +use opentelemetry::trace::TraceContextExt; use request::convert_steps; use request::Request; use serde::Deserialize; @@ -24,6 +25,8 @@ use serde::Serialize; use std::collections::HashMap; use std::sync::Arc; use thiserror::Error; +use tracing::Instrument; +use tracing_opentelemetry::OpenTelemetrySpanExt; use utoipa::IntoParams; use utoipa::ToSchema; @@ -36,6 +39,7 @@ use crate::core::simulation::{RoutingRequirement, SimulationResponse, SpacingReq use crate::core::AsCoreRequest; use crate::core::CoreClient; use crate::error::Result; +use crate::models::stdcm_log::StdcmLog; use crate::models::timetable::TimetableWithTrains; use crate::models::train_schedule::TrainSchedule; use crate::models::Infra; @@ -46,10 +50,13 @@ use crate::views::train_schedule::train_simulation_batch; use crate::views::AuthenticationExt; use crate::views::AuthorizationError; use crate::AppState; +use crate::Model; use crate::Retrieve; use crate::RetrieveBatch; use crate::ValkeyClient; +use super::Create; + editoast_common::schemas! { request::schemas(), } @@ -135,7 +142,7 @@ async fn stdcm( } let db_pool = app_state.db_pool_v2.clone(); - let conn = &mut db_pool.get().await?; + let conn = &mut db_pool.clone().get().await?; let valkey_client = app_state.valkey.clone(); let core_client = app_state.core_client.clone(); @@ -251,7 +258,34 @@ async fn stdcm( let stdcm_response = stdcm_request.fetch(core_client.as_ref()).await?; - // 6. Handle STDCM Core Response + // 6. Check if the current tracing level is debug or lower, and if so, log STDCM request and response + if tracing::Level::DEBUG <= tracing::level_filters::LevelFilter::current() { + let stdcm_response_for_spawn = stdcm_response.clone(); + let _ = tokio::spawn( + async move { + match &mut db_pool.get().await { + Ok(conn) => { + let trace_id = tracing::Span::current() + .context() + .span() + .span_context() + .trace_id(); + let _ = StdcmLog::changeset() + .trace_id(trace_id.to_string()) + .request(stdcm_request) + .response(stdcm_response_for_spawn) + .create(conn) + .await; + } + Err(_) => tracing::warn!("Database connection failed during log operation."), + } + } + .in_current_span(), + ) + .await; + } + + // 7. Handle STDCM Core Response match stdcm_response { crate::core::stdcm::Response::Success { simulation,