diff --git a/Framework/Core/include/Framework/DeviceControl.h b/Framework/Core/include/Framework/DeviceControl.h index 589de3937ee55..ce946e8e77fbf 100644 --- a/Framework/Core/include/Framework/DeviceControl.h +++ b/Framework/Core/include/Framework/DeviceControl.h @@ -48,6 +48,8 @@ struct DeviceControl { DeviceController* controller = nullptr; /// What kind of events should run with the TRACE level int tracingFlags = 0; + /// What kind of log streams should be enabled + int logStreams = 0; /// An incremental number to identify the device state int requestedState = 0; }; diff --git a/Framework/Core/include/Framework/DeviceState.h b/Framework/Core/include/Framework/DeviceState.h index 3be0302fd4113..4fa72a84cad71 100644 --- a/Framework/Core/include/Framework/DeviceState.h +++ b/Framework/Core/include/Framework/DeviceState.h @@ -57,6 +57,13 @@ struct DeviceState { DATA_CONNECTED = 1 << 19, // Data channel connected }; + enum LogStreams : int { + NO_LOG = 0, + DEVICE_LOG = 1 << 0, // Log for Data Processing Device activities. + COMPLETION_LOG = 1 << 1, // Log for the completion policy of the device. + MONITORING_SERVICE_LOG = 1 << 2, // Log for the monitoring service flushing. + }; + std::vector inputChannelInfos; StreamingState streaming = StreamingState::Streaming; bool quitRequested = false; @@ -93,6 +100,8 @@ struct DeviceState { int loopReason = 0; /// Bitmask of LoopReason to trace int tracingFlags = 0; + /// Bitmask of log streams which are available + int logStreams = 0; /// Stack of the severity, so that we can display only /// the bits we are interested in. std::vector severityStack; diff --git a/Framework/Core/src/WSDriverClient.cxx b/Framework/Core/src/WSDriverClient.cxx index d4ed77b9a004e..234b98b10259d 100644 --- a/Framework/Core/src/WSDriverClient.cxx +++ b/Framework/Core/src/WSDriverClient.cxx @@ -16,10 +16,15 @@ #include "Framework/DeviceSpec.h" #include "DriverClientContext.h" #include "DPLWebSocket.h" +#include "Framework/Signpost.h" #include #include #include +O2_DECLARE_DYNAMIC_LOG(device); +O2_DECLARE_DYNAMIC_LOG(completion); +O2_DECLARE_DYNAMIC_LOG(monitoring_service); + namespace o2::framework { @@ -152,6 +157,42 @@ void on_connect(uv_connect_t* connection, int status) state.tracingFlags = tracingFlags; }); + client->observe("/log-streams", [ref = context->ref](std::string_view cmd) { + auto& state = ref.get(); + static constexpr int prefixSize = std::string_view{"/log-streams "}.size(); + if (prefixSize > cmd.size()) { + LOG(error) << "Malformed log-streams request"; + return; + } + cmd.remove_prefix(prefixSize); + int logStreams = 0; + + auto error = std::from_chars(cmd.data(), cmd.data() + cmd.size(), logStreams); + if (error.ec != std::errc()) { + LOG(error) << "Malformed log-streams mask"; + return; + } + LOGP(info, "Logstreams flags set to {}", logStreams); + state.logStreams = logStreams; + if ((state.logStreams & DeviceState::LogStreams::DEVICE_LOG) != 0) { + O2_LOG_ENABLE(device); + } else { + O2_LOG_DISABLE(device); + } + if ((state.logStreams & DeviceState::LogStreams::COMPLETION_LOG) != 0) { + O2_LOG_ENABLE(completion); + } else { + O2_LOG_DISABLE(completion); + } + + if ((state.logStreams & DeviceState::LogStreams::MONITORING_SERVICE_LOG) != 0) { + O2_LOG_ENABLE(monitoring_service); + } else { + O2_LOG_DISABLE(monitoring_service); + } + + }); + // Client will be filled in the line after. I can probably have a single // client per device. auto dplClient = std::make_unique(); diff --git a/Framework/GUISupport/src/FrameworkGUIDeviceInspector.cxx b/Framework/GUISupport/src/FrameworkGUIDeviceInspector.cxx index a82753eb5af1f..fe93ca6d0f07f 100644 --- a/Framework/GUISupport/src/FrameworkGUIDeviceInspector.cxx +++ b/Framework/GUISupport/src/FrameworkGUIDeviceInspector.cxx @@ -400,6 +400,17 @@ void displayDeviceInspector(DeviceSpec const& spec, } } + bool logsChanged = false; + if (ImGui::CollapsingHeader("Signposts", ImGuiTreeNodeFlags_DefaultOpen)) { + logsChanged = ImGui::CheckboxFlags("Device", &control.logStreams, DeviceState::LogStreams::DEVICE_LOG); + logsChanged = ImGui::CheckboxFlags("Completion", &control.logStreams, DeviceState::LogStreams::COMPLETION_LOG); + logsChanged = ImGui::CheckboxFlags("Monitoring", &control.logStreams, DeviceState::LogStreams::MONITORING_SERVICE_LOG); + if (logsChanged && control.controller) { + std::string cmd = fmt::format("/log-streams {}", control.logStreams); + control.controller->write(cmd.c_str(), cmd.size()); + } + } + bool flagsChanged = false; if (ImGui::CollapsingHeader("Event loop tracing", ImGuiTreeNodeFlags_DefaultOpen)) { flagsChanged |= ImGui::CheckboxFlags("METRICS_MUST_FLUSH", &control.tracingFlags, DeviceState::LoopReason::METRICS_MUST_FLUSH); diff --git a/Framework/TestWorkflows/test/test_DetectMissingTimeframe.cxx b/Framework/TestWorkflows/test/test_DetectMissingTimeframe.cxx index 3374cd9ad6cf2..7ef1370f040b4 100644 --- a/Framework/TestWorkflows/test/test_DetectMissingTimeframe.cxx +++ b/Framework/TestWorkflows/test/test_DetectMissingTimeframe.cxx @@ -43,6 +43,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& specs) if (i++ % 2 == 0) { outputs.make(OutputRef{"a2"}, 1); } + sleep(1); })}, }; DataProcessorSpec d{