Skip to content

Commit b5e5498

Browse files
authored
Feat: add FromEnv::inventory() (#7)
* feat: inventory on fromenv * feat: more info * docs: more of em
1 parent 949dc28 commit b5e5498

File tree

7 files changed

+129
-4
lines changed

7 files changed

+129
-4
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ name = "init4-bin-base"
44
description = "Internal utilities for binaries produced by the init4 team"
55
keywords = ["init4", "bin", "base"]
66

7-
version = "0.1.4"
7+
version = "0.2.0"
88
edition = "2021"
99
rust-version = "1.81"
1010
authors = ["init4", "James Prestwich"]

src/perms/builders.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::{
1010
perms::{SlotAuthzConfig, SlotAuthzConfigError},
1111
utils::{
1212
calc::SlotCalculator,
13-
from_env::{FromEnv, FromEnvErr, FromEnvVar},
13+
from_env::{EnvItemInfo, FromEnv, FromEnvErr, FromEnvVar},
1414
},
1515
};
1616

@@ -173,6 +173,18 @@ impl Builders {
173173
impl FromEnv for Builders {
174174
type Error = BuilderConfigError;
175175

176+
fn inventory() -> Vec<&'static EnvItemInfo> {
177+
let mut v = vec![
178+
&EnvItemInfo {
179+
var: BUILDERS,
180+
description: "A comma-separated list of UUIDs representing the builders that are allowed to perform actions.",
181+
optional: false,
182+
},
183+
];
184+
v.extend(SlotAuthzConfig::inventory());
185+
v
186+
}
187+
176188
fn from_env() -> Result<Self, FromEnvErr<Self::Error>> {
177189
let s = String::from_env_var(BUILDERS)
178190
.map_err(FromEnvErr::infallible_into::<BuilderConfigError>)?;

src/perms/config.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::utils::{
22
calc::{SlotCalcEnvError, SlotCalculator},
3-
from_env::{FromEnv, FromEnvErr, FromEnvVar},
3+
from_env::{EnvItemInfo, FromEnv, FromEnvErr, FromEnvVar},
44
};
55
use core::num;
66

@@ -76,6 +76,21 @@ impl SlotAuthzConfig {
7676
impl FromEnv for SlotAuthzConfig {
7777
type Error = SlotAuthzConfigError;
7878

79+
fn inventory() -> Vec<&'static EnvItemInfo> {
80+
let mut v = vec![
81+
&EnvItemInfo {
82+
var: BLOCK_QUERY_CUTOFF,
83+
description: "The block query cutoff time in seconds. This is the slot second after which requests will not be serviced. E.g. a value of 1 means that requests will not be serviced for the last second of any given slot.",
84+
optional: false,
85+
}, &EnvItemInfo {
86+
var: BLOCK_QUERY_START,
87+
description: "The block query start time in seconds. This is the slot second before which requests will not be serviced. E.g. a value of 1 means that requests will not be serviced for the first second of any given slot.",
88+
optional: false,
89+
}];
90+
v.extend(SlotCalculator::inventory());
91+
v
92+
}
93+
7994
fn from_env() -> Result<Self, FromEnvErr<Self::Error>> {
8095
let calc = SlotCalculator::from_env().map_err(FromEnvErr::from)?;
8196
let block_query_cutoff = u8::from_env_var(BLOCK_QUERY_CUTOFF)

src/utils/calc.rs

+22
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use crate::utils::from_env::{FromEnv, FromEnvErr, FromEnvVar};
22
use core::num;
33

4+
use super::from_env::EnvItemInfo;
5+
46
// Env vars
57
pub(crate) const START_TIMESTAMP: &str = "START_TIMESTAMP";
68
pub(crate) const SLOT_OFFSET: &str = "SLOT_OFFSET";
@@ -125,6 +127,26 @@ impl SlotCalculator {
125127
impl FromEnv for SlotCalculator {
126128
type Error = SlotCalcEnvError;
127129

130+
fn inventory() -> Vec<&'static EnvItemInfo> {
131+
vec![
132+
&EnvItemInfo {
133+
var: START_TIMESTAMP,
134+
description: "The start timestamp of the chain in seconds",
135+
optional: false,
136+
},
137+
&EnvItemInfo {
138+
var: SLOT_OFFSET,
139+
description: "The slot offset of the chain in seconds",
140+
optional: false,
141+
},
142+
&EnvItemInfo {
143+
var: SLOT_DURATION,
144+
description: "The slot duration of the chain in seconds",
145+
optional: false,
146+
},
147+
]
148+
}
149+
128150
fn from_env() -> Result<Self, FromEnvErr<Self::Error>> {
129151
let start_timestamp = u64::from_env_var(START_TIMESTAMP)
130152
.map_err(|e| e.map(SlotCalcEnvError::StartTimestamp))?;

src/utils/from_env.rs

+40
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
use std::{convert::Infallible, env::VarError, num::ParseIntError, str::FromStr};
22

3+
/// Details about an environment variable. This is used to generate
4+
/// documentation for the environment variables and by the [`FromEnv`] trait to
5+
/// check if necessary environment variables are present.
6+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7+
pub struct EnvItemInfo {
8+
/// The environment variable name.
9+
pub var: &'static str,
10+
/// A description of the environment variable function in the CFG.
11+
pub description: &'static str,
12+
/// Whether the environment variable is optional or not.
13+
pub optional: bool,
14+
}
15+
316
/// Error type for loading from the environment. See the [`FromEnv`] trait for
417
/// more information.
518
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
@@ -93,6 +106,33 @@ pub trait FromEnv: core::fmt::Debug + Sized + 'static {
93106
/// Error type produced when loading from the environment.
94107
type Error: core::error::Error;
95108

109+
/// Get the required environment variable names for this type.
110+
///
111+
/// ## Note
112+
///
113+
/// This MUST include the environment variable names for all fields in the
114+
/// struct, including optional vars.
115+
fn inventory() -> Vec<&'static EnvItemInfo>;
116+
117+
/// Get a list of missing environment variables.
118+
///
119+
/// This will check all environment variables in the inventory, and return
120+
/// a list of those that are non-optional and missing. This is useful for
121+
/// reporting missing environment variables.
122+
fn check_inventory() -> Result<(), Vec<&'static EnvItemInfo>> {
123+
let mut missing = Vec::new();
124+
for var in Self::inventory() {
125+
if std::env::var(var.var).is_err() && !var.optional {
126+
missing.push(var);
127+
}
128+
}
129+
if missing.is_empty() {
130+
Ok(())
131+
} else {
132+
Err(missing)
133+
}
134+
}
135+
96136
/// Load from the environment.
97137
fn from_env() -> Result<Self, FromEnvErr<Self::Error>>;
98138
}

src/utils/metrics.rs

+10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use crate::utils::from_env::{FromEnv, FromEnvErr, FromEnvVar};
22
use metrics_exporter_prometheus::PrometheusBuilder;
33

4+
use super::from_env::EnvItemInfo;
5+
46
/// Metrics port env var
57
const METRICS_PORT: &str = "METRICS_PORT";
68

@@ -40,6 +42,14 @@ impl From<u16> for MetricsConfig {
4042
impl FromEnv for MetricsConfig {
4143
type Error = std::num::ParseIntError;
4244

45+
fn inventory() -> Vec<&'static EnvItemInfo> {
46+
vec![&EnvItemInfo {
47+
var: METRICS_PORT,
48+
description: "Port on which to serve metrics, u16, defaults to 9000",
49+
optional: true,
50+
}]
51+
}
52+
4353
fn from_env() -> Result<Self, FromEnvErr<Self::Error>> {
4454
match u16::from_env_var(METRICS_PORT).map(Self::from) {
4555
Ok(cfg) => Ok(cfg),

src/utils/otlp.rs

+27-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::utils::from_env::{FromEnv, FromEnvErr, FromEnvVar};
1+
use crate::utils::from_env::{EnvItemInfo, FromEnv, FromEnvErr, FromEnvVar};
22
use opentelemetry::{trace::TracerProvider, KeyValue};
33
use opentelemetry_sdk::trace::SdkTracerProvider;
44
use opentelemetry_sdk::Resource;
@@ -110,6 +110,32 @@ pub struct OtelConfig {
110110
impl FromEnv for OtelConfig {
111111
type Error = url::ParseError;
112112

113+
fn inventory() -> Vec<&'static EnvItemInfo> {
114+
vec![
115+
&EnvItemInfo {
116+
var: OTEL_ENDPOINT,
117+
description:
118+
"OTLP endpoint to send traces to, a url. If missing, disables OTLP exporting.",
119+
optional: true,
120+
},
121+
&EnvItemInfo {
122+
var: OTEL_LEVEL,
123+
description: "OTLP level to export, defaults to DEBUG. Permissible values are: TRACE, DEBUG, INFO, WARN, ERROR, OFF",
124+
optional: true,
125+
},
126+
&EnvItemInfo {
127+
var: OTEL_TIMEOUT,
128+
description: "OTLP timeout in milliseconds",
129+
optional: true,
130+
},
131+
&EnvItemInfo {
132+
var: OTEL_ENVIRONMENT,
133+
description: "OTLP environment name, a string",
134+
optional: true,
135+
},
136+
]
137+
}
138+
113139
fn from_env() -> Result<Self, FromEnvErr<Self::Error>> {
114140
// load endpoint from env. ignore empty values (shortcut return None), parse, and print the error if any using inspect_err
115141
let endpoint = Url::from_env_var(OTEL_ENDPOINT).inspect_err(|e| eprintln!("{e}"))?;

0 commit comments

Comments
 (0)