Skip to main content

openjd_sessions/
logging.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// Copyright by contributors to this project.
3// SPDX-License-Identifier: (Apache-2.0 OR MIT)
4
5//! Structured logging with content classification.
6//!
7//! Mirrors Python's `openjd.sessions._logging.LogContent(Flag)`.
8//! The worker agent uses `openjd_log_content` to route log records:
9//! only EXCEPTION_INFO | PROCESS_CONTROL | HOST_INFO go to the worker log;
10//! all records go to CloudWatch via the session log stream.
11
12use bitflags::bitflags;
13
14bitflags! {
15    /// Describes the content of a log record, used by consumers to filter/route logs.
16    ///
17    /// ```
18    /// use openjd_sessions::LogContent;
19    ///
20    /// let content = LogContent::COMMAND_OUTPUT | LogContent::PROCESS_CONTROL;
21    /// assert!(content.contains(LogContent::COMMAND_OUTPUT));
22    /// assert!(!content.contains(LogContent::BANNER));
23    /// ```
24    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
25    pub struct LogContent: u32 {
26        const BANNER = 1 << 0;
27        const FILE_PATH = 1 << 1;
28        const FILE_CONTENTS = 1 << 2;
29        const COMMAND_OUTPUT = 1 << 3;
30        const EXCEPTION_INFO = 1 << 4;
31        const PROCESS_CONTROL = 1 << 5;
32        const PARAMETER_INFO = 1 << 6;
33        const HOST_INFO = 1 << 7;
34    }
35}
36
37impl log::kv::ToValue for LogContent {
38    fn to_value(&self) -> log::kv::Value<'_> {
39        log::kv::Value::from(self.bits())
40    }
41}
42
43/// Emit a structured log record with session_id, openjd_log_content, and
44/// a precise timestamp captured at the point of the log call.
45///
46/// Usage:
47///   session_log!(info, session_id, LogContent::HOST_INFO, "message {}", arg);
48#[macro_export]
49macro_rules! session_log {
50    ($level:ident, $session_id:expr, $content:expr, $($arg:tt)+) => {
51        log::$level!(
52            target: "openjd.sessions",
53            session_id = $session_id,
54            openjd_log_content = $crate::logging::LogContent::bits(&$content),
55            openjd_timestamp_usec = $crate::logging::timestamp_usec();
56            $($arg)+
57        )
58    };
59}
60
61/// Return the current time as microseconds since the Unix epoch (u64).
62/// Used by `session_log!` to attach a precise timestamp to each log record.
63pub fn timestamp_usec() -> u64 {
64    std::time::SystemTime::now()
65        .duration_since(std::time::UNIX_EPOCH)
66        .unwrap_or_default()
67        .as_micros() as u64
68}
69
70/// Log a section banner (major section separator).
71pub fn log_section_banner(session_id: &str, title: &str) {
72    session_log!(info, session_id, LogContent::BANNER, "");
73    session_log!(
74        info,
75        session_id,
76        LogContent::BANNER,
77        "=============================================="
78    );
79    session_log!(info, session_id, LogContent::BANNER, "--------- {}", title);
80    session_log!(
81        info,
82        session_id,
83        LogContent::BANNER,
84        "=============================================="
85    );
86}
87
88/// Log a subsection banner (minor section separator).
89pub fn log_subsection_banner(session_id: &str, title: &str) {
90    session_log!(
91        info,
92        session_id,
93        LogContent::BANNER,
94        "----------------------------------------------"
95    );
96    session_log!(info, session_id, LogContent::BANNER, "{}", title);
97    session_log!(
98        info,
99        session_id,
100        LogContent::BANNER,
101        "----------------------------------------------"
102    );
103}