vector/
generate_schema.rs

1//! Vector `generate-schema` command implementation.
2
3use std::{fs, path::PathBuf};
4
5use clap::Parser;
6use serde_json::{Value, json};
7use vector_common::internal_event::{CounterName, GaugeName, HistogramName};
8use vector_lib::configurable::schema::generate_root_schema;
9
10use crate::config::ConfigBuilder;
11
12#[derive(Parser, Debug)]
13#[command(rename_all = "kebab-case")]
14/// Command line options for the `generate-schema` command.
15pub struct Opts {
16    /// File path to
17    #[arg(short, long)]
18    pub(crate) output_path: Option<PathBuf>,
19}
20
21fn metric_enum_schema<T: vector_lib::configurable::Configurable + 'static>() -> Value {
22    generate_root_schema::<T>()
23        .map(|s| serde_json::to_value(s).unwrap_or(Value::Null))
24        .unwrap_or(Value::Null)
25}
26
27/// Execute the `generate-schema` command.
28#[allow(clippy::print_stdout, clippy::print_stderr)]
29pub fn cmd(opts: &Opts) -> exitcode::ExitCode {
30    match generate_root_schema::<ConfigBuilder>() {
31        Ok(config_schema) => {
32            // Convert to Value so we can inject the metric enum schemas.
33            let mut schema = serde_json::to_value(config_schema)
34                .expect("rendering root schema to JSON should not fail");
35
36            // Inject metric name enum schemas so vdev can generate
37            // internal_metrics.cue output descriptions from them.
38            schema["_metric_schemas"] = json!({
39                "counters":   metric_enum_schema::<CounterName>(),
40                "histograms": metric_enum_schema::<HistogramName>(),
41                "gauges":     metric_enum_schema::<GaugeName>(),
42            });
43
44            let json = serde_json::to_string_pretty(&schema)
45                .expect("rendering root schema to JSON should not fail");
46
47            if let Some(output_path) = &opts.output_path {
48                if output_path.exists() {
49                    eprintln!("Error: Output file {output_path:?} already exists");
50                    return exitcode::CANTCREAT;
51                }
52
53                return match fs::write(output_path, json) {
54                    Ok(_) => {
55                        println!("Schema successfully written to {output_path:?}");
56                        exitcode::OK
57                    }
58                    Err(e) => {
59                        eprintln!("Error writing to file {output_path:?}: {e:?}");
60                        exitcode::IOERR
61                    }
62                };
63            } else {
64                println!("{json}");
65            }
66            exitcode::OK
67        }
68        Err(e) => {
69            eprintln!("error while generating schema: {e:?}");
70            exitcode::SOFTWARE
71        }
72    }
73}