ghactions_core/
logging.rs

1//! Logging utilities for GitHub Actions
2use env_logger::Builder;
3use std::env;
4use std::io::Write;
5
6/// Initialise and create a `env_logger::Builder` which follows the
7/// GitHub Actions logging syntax.
8///
9pub fn init_logger() -> Builder {
10    let mut builder = Builder::from_default_env();
11
12    // Make sure the target is STDOUT
13    builder.target(env_logger::Target::Stdout);
14
15    // Find and setup the correct log level
16    builder.filter(None, get_log_level());
17    builder.write_style(env_logger::WriteStyle::Always);
18
19    // Custom Formatter for Actions
20    builder.format(|buf, record| match record.level().as_str() {
21        "DEBUG" => writeln!(buf, "::debug :: {}", record.args()),
22        "WARN" => writeln!(buf, "::warning :: {}", record.args()),
23        "ERROR" => {
24            writeln!(buf, "::error :: {}", record.args())
25        }
26        _ => writeln!(buf, "{}", record.args()),
27    });
28
29    builder
30}
31
32/// Get the Log Level for the logger
33fn get_log_level() -> log::LevelFilter {
34    // DEBUG
35    match env::var("DEBUG") {
36        Ok(_value) => return log::LevelFilter::Debug,
37        Err(_err) => (),
38    }
39    // ACTIONS_RUNNER_DEBUG
40    match env::var("ACTIONS_RUNNER_DEBUG") {
41        Ok(_value) => return log::LevelFilter::Debug,
42        Err(_err) => (),
43    };
44
45    log::LevelFilter::Info
46}
47
48/// Error for files (including line and column numbers)
49///
50/// # Examples
51///
52/// ```
53/// use ghactions::errorf;
54///
55/// # fn foo() {
56/// errorf!(
57///     file: "src/main.rs",
58///     line: 0,
59///     column: 0,
60///     "Error checking file"
61/// );
62/// # }
63/// ```
64#[macro_export(local_inner_macros)]
65macro_rules! errorf {
66    // errorf!(file: "./lib.rs", line: 0, column: 0, "Sample Error")
67    (file: $file:expr, line: $line:expr, column: $column:expr, $msg:tt) => {
68        ::log::log!(::log::Level::Info, "::error file={},line={},col={} :: {}", $file, $line, $column, $msg)
69    };
70    // errorf!("a {} event", "log")
71    ($($arg:tt)+) => (::log::log!($crate::Level::Error, $($arg)+))
72}
73
74/// Group Macros
75///
76/// # Examples
77///
78/// ```
79/// use ghactions::group;
80///
81/// # fn foo() {
82/// group!("working group");
83/// # }
84/// ```
85#[macro_export(local_inner_macros)]
86macro_rules! group {
87    // group!("Group name")
88    ($dst:expr $(,)?) => {
89        ::log::log!(log::Level::Info, "::group::{}", $dst)
90    };
91}
92
93/// End Group Macros
94///
95/// # Examples
96///
97/// ```
98/// use ghactions::groupend;
99///
100/// # fn foo() {
101/// groupend!();
102/// # }
103
104/// ```
105#[macro_export(local_inner_macros)]
106macro_rules! groupend {
107    // group_end!()
108    () => {
109        ::log::log!(log::Level::Info, "::endgroup::")
110    };
111}
112
113/// Sets the output of the Actions which can be used in subsequent Actions.
114///
115/// # Examples
116///
117/// ```rust
118/// use ghactions::setoutput;
119///
120/// # fn foo() {
121/// setoutput!("hello", "world");
122/// # }
123/// ```
124#[macro_export(local_inner_macros)]
125macro_rules! setoutput {
126    // setoutput!("name", "value")
127    ($($arg:tt)+) => {
128        {
129            use std::io::Write;
130            let output = ::std::format!("::set-output name={}::{}", $($arg)+);
131            #[cfg(feature = "log")]
132            {
133                ::log::log!(::log::Level::Info, "{}", output);
134            }
135
136            let output_file = std::env::var("GITHUB_OUTPUT").unwrap_or_else(|_| "/tmp/github_actions.env".to_string());
137            // Append to the file
138            let mut file = std::fs::OpenOptions::new()
139                .create(true)
140                .append(true)
141                .open(output_file)
142                .unwrap();
143            // Append to end of file
144            ::std::writeln!(file, "{}", output).unwrap();
145        }
146    }
147}