generated from Patagia/template-nix
Compare commits
No commits in common. "441c38b3d5f235f71cebb25626e396f6209f15c0" and "da210ffc166c3f0d3029b93036ace00b7a8155c8" have entirely different histories.
441c38b3d5
...
da210ffc16
13 changed files with 36 additions and 246 deletions
47
Cargo.lock
generated
47
Cargo.lock
generated
|
@ -1110,21 +1110,6 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instrumentation"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"http",
|
||||
"once_cell",
|
||||
"opentelemetry",
|
||||
"opentelemetry-otlp",
|
||||
"opentelemetry-semantic-conventions",
|
||||
"opentelemetry_sdk",
|
||||
"tracing-opentelemetry",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ipnet"
|
||||
version = "2.10.1"
|
||||
|
@ -1527,7 +1512,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"instrumentation",
|
||||
"patagia-common",
|
||||
"progenitor",
|
||||
"reqwest",
|
||||
"schemars",
|
||||
|
@ -1536,6 +1521,20 @@ dependencies = [
|
|||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "patagia-common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"once_cell",
|
||||
"opentelemetry",
|
||||
"opentelemetry-otlp",
|
||||
"opentelemetry-semantic-conventions",
|
||||
"opentelemetry_sdk",
|
||||
"tracing-opentelemetry",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "patagia-controller"
|
||||
version = "0.1.0"
|
||||
|
@ -1543,14 +1542,12 @@ dependencies = [
|
|||
"anyhow",
|
||||
"clap",
|
||||
"dropshot",
|
||||
"http",
|
||||
"instrumentation",
|
||||
"patagia-common",
|
||||
"schemars",
|
||||
"serde",
|
||||
"slog",
|
||||
"slog-async",
|
||||
"tokio",
|
||||
"trace-request",
|
||||
"tracing",
|
||||
"tracing-slog",
|
||||
]
|
||||
|
@ -2741,18 +2738,6 @@ version = "0.3.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
|
||||
|
||||
[[package]]
|
||||
name = "trace-request"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"dropshot",
|
||||
"http",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.41"
|
||||
|
|
|
@ -2,16 +2,14 @@
|
|||
resolver = "2"
|
||||
members = [
|
||||
"agent",
|
||||
"common",
|
||||
"controller",
|
||||
"instrumentation",
|
||||
"trace-request",
|
||||
"xtask",
|
||||
]
|
||||
default-members = [
|
||||
"agent",
|
||||
"common",
|
||||
"controller",
|
||||
"instrumentation",
|
||||
"trace-request",
|
||||
"xtask",
|
||||
]
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ license = "MPL-2.0"
|
|||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
clap.workspace = true
|
||||
instrumentation = { path = "../instrumentation" }
|
||||
patagia-common = { path = "../common" }
|
||||
progenitor.workspace = true
|
||||
reqwest.workspace = true
|
||||
schemars.workspace = true
|
||||
|
|
|
@ -3,6 +3,7 @@ use clap::Parser;
|
|||
use tokio::time::{sleep, Duration};
|
||||
|
||||
mod patagia_api;
|
||||
use patagia_common::instrumentation;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(version, about, long_about = None)]
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
[package]
|
||||
name = "instrumentation"
|
||||
name = "patagia-common"
|
||||
description = "Common control plane modules"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license = "MPL-2.0"
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
http.workspace = true
|
||||
once_cell.workspace = true
|
||||
opentelemetry-otlp.workspace = true
|
||||
opentelemetry_sdk.workspace = true
|
1
common/src/lib.rs
Normal file
1
common/src/lib.rs
Normal file
|
@ -0,0 +1 @@
|
|||
pub mod instrumentation;
|
|
@ -9,16 +9,11 @@ license = "MPL-2.0"
|
|||
anyhow.workspace = true
|
||||
clap.workspace = true
|
||||
dropshot.workspace = true
|
||||
http.workspace = true
|
||||
instrumentation = { path = "../instrumentation" }
|
||||
patagia-common = { path = "../common" }
|
||||
schemars.workspace = true
|
||||
serde.workspace = true
|
||||
slog-async.workspace = true
|
||||
slog.workspace = true
|
||||
tokio.workspace = true
|
||||
trace-request = { path = "../trace-request" }
|
||||
tracing-slog.workspace = true
|
||||
tracing.workspace = true
|
||||
|
||||
[package.metadata.cargo-machete]
|
||||
ignored = ["http"]
|
||||
|
|
|
@ -9,6 +9,7 @@ use std::net::SocketAddr;
|
|||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use patagia_common::instrumentation;
|
||||
use patagia_controller::api;
|
||||
use patagia_controller::context::ControllerContext;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use dropshot::{endpoint, HttpError, HttpResponseOk, RequestContext};
|
||||
use schemars::JsonSchema;
|
||||
use serde::Serialize;
|
||||
use trace_request::trace_request;
|
||||
use tracing::Instrument;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -19,7 +19,16 @@ struct VersionInfo {
|
|||
method = GET,
|
||||
path = "/version",
|
||||
}]
|
||||
#[trace_request]
|
||||
#[tracing::instrument(
|
||||
skip(rqctx),
|
||||
fields(
|
||||
http.method=rqctx.request.method().as_str(),
|
||||
http.path=rqctx.request.uri().path(),
|
||||
http.remote_ip=rqctx.request.remote_addr().ip().to_string(),
|
||||
request_id = rqctx.request_id,
|
||||
),
|
||||
err(Debug),
|
||||
)]
|
||||
pub(crate) async fn version(
|
||||
rqctx: RequestContext<Arc<ControllerContext>>,
|
||||
) -> Result<HttpResponseOk<VersionInfo>, HttpError> {
|
||||
|
@ -36,6 +45,5 @@ pub(crate) async fn version(
|
|||
}
|
||||
.instrument(tracing::info_span!("Let's do the thing...."))
|
||||
.await;
|
||||
|
||||
Ok(HttpResponseOk(ver))
|
||||
}
|
||||
|
|
|
@ -1,102 +0,0 @@
|
|||
use anyhow::{anyhow, Result};
|
||||
use once_cell::sync::Lazy;
|
||||
use opentelemetry::{trace::TracerProvider as _, KeyValue};
|
||||
use opentelemetry_sdk::{
|
||||
metrics::{MeterProviderBuilder, PeriodicReader, SdkMeterProvider},
|
||||
runtime,
|
||||
trace::{RandomIdGenerator, Sampler, TracerProvider},
|
||||
Resource,
|
||||
};
|
||||
use tracing_opentelemetry::{MetricsLayer, OpenTelemetryLayer};
|
||||
use tracing_subscriber::layer::SubscriberExt;
|
||||
use tracing_subscriber::util::SubscriberInitExt;
|
||||
|
||||
static RESOURCE: Lazy<Resource> = Lazy::new(|| {
|
||||
Resource::new(vec![
|
||||
KeyValue::new(
|
||||
opentelemetry_semantic_conventions::resource::SERVICE_NAME,
|
||||
env!("CARGO_PKG_NAME"),
|
||||
),
|
||||
KeyValue::new(
|
||||
opentelemetry_semantic_conventions::resource::SERVICE_VERSION,
|
||||
env!("CARGO_PKG_VERSION"),
|
||||
),
|
||||
])
|
||||
});
|
||||
|
||||
// Construct MeterProvider for MetricsLayer
|
||||
fn init_meter_provider() -> Result<SdkMeterProvider> {
|
||||
let exporter = opentelemetry_otlp::MetricExporter::builder()
|
||||
.with_tonic()
|
||||
.with_temporality(opentelemetry_sdk::metrics::Temporality::default())
|
||||
.build()
|
||||
.map_err(|e| anyhow!("Error creating OTLP metric exporter: {:?}", e))?;
|
||||
|
||||
let meter_provider = MeterProviderBuilder::default()
|
||||
.with_resource(RESOURCE.clone())
|
||||
.with_reader(
|
||||
PeriodicReader::builder(exporter, runtime::Tokio)
|
||||
.with_interval(std::time::Duration::from_secs(10))
|
||||
.build(),
|
||||
)
|
||||
.build();
|
||||
|
||||
opentelemetry::global::set_meter_provider(meter_provider.clone());
|
||||
|
||||
Ok(meter_provider)
|
||||
}
|
||||
|
||||
// Construct TracerProvider for OpenTelemetryLayer
|
||||
fn init_tracer_provider() -> Result<TracerProvider> {
|
||||
let exporter = opentelemetry_otlp::SpanExporter::builder()
|
||||
.with_tonic()
|
||||
.build()
|
||||
.map_err(|e| anyhow!("Error creating OTLP span exporter: {:?}", e))?;
|
||||
|
||||
let tracer_provider = opentelemetry_sdk::trace::TracerProvider::builder()
|
||||
.with_sampler(Sampler::ParentBased(Box::new(Sampler::TraceIdRatioBased(
|
||||
1.0,
|
||||
))))
|
||||
.with_resource(RESOURCE.clone())
|
||||
.with_id_generator(RandomIdGenerator::default())
|
||||
.with_batch_exporter(exporter, opentelemetry_sdk::runtime::Tokio)
|
||||
.build();
|
||||
|
||||
Ok(tracer_provider)
|
||||
}
|
||||
|
||||
// Initialize tracing-subscriber and return OtelGuard for opentelemetry-related termination processing
|
||||
pub fn init_tracing_subscriber() -> Result<OtelGuard> {
|
||||
let meter_provider = init_meter_provider()?;
|
||||
let tracer_provider = init_tracer_provider()?;
|
||||
|
||||
let tracer = tracer_provider.tracer("tracing-otel-subscriber");
|
||||
|
||||
tracing_subscriber::registry()
|
||||
.with(tracing_subscriber::EnvFilter::from_default_env())
|
||||
.with(tracing_subscriber::fmt::layer())
|
||||
.with(MetricsLayer::new(meter_provider.clone()))
|
||||
.with(OpenTelemetryLayer::new(tracer))
|
||||
.init();
|
||||
|
||||
Ok(OtelGuard {
|
||||
meter_provider,
|
||||
tracer_provider,
|
||||
})
|
||||
}
|
||||
|
||||
pub struct OtelGuard {
|
||||
meter_provider: SdkMeterProvider,
|
||||
tracer_provider: TracerProvider,
|
||||
}
|
||||
|
||||
impl Drop for OtelGuard {
|
||||
fn drop(&mut self) {
|
||||
if let Err(err) = self.tracer_provider.shutdown() {
|
||||
eprintln!("{err:?}");
|
||||
}
|
||||
if let Err(err) = self.meter_provider.shutdown() {
|
||||
eprintln!("{err:?}");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
[package]
|
||||
name = "trace-request"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license = "MPL-2.0"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = "1"
|
||||
quote = "1"
|
||||
syn = { version = "2.0", features = ["full"] }
|
||||
|
||||
[dev-dependencies]
|
||||
dropshot = { workspace = true }
|
||||
http = { workspace = true }
|
||||
tracing = { workspace = true }
|
|
@ -1,79 +0,0 @@
|
|||
// Original source: https://github.com/oxidecomputer/rfd-api/blob/main/trace-request/src/lib.rs
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
#![allow(dead_code, unused_imports)]
|
||||
|
||||
extern crate proc_macro;
|
||||
#[macro_use]
|
||||
extern crate quote;
|
||||
|
||||
use std::result::Iter;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro2::{Delimiter, Group, Span, TokenTree};
|
||||
use quote::ToTokens;
|
||||
use syn::{
|
||||
bracketed,
|
||||
parse::{Parse, ParseStream, Parser},
|
||||
parse_macro_input,
|
||||
punctuated::Punctuated,
|
||||
Block, DeriveInput, Ident, ItemFn, LitStr, Result, Token, Type,
|
||||
};
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn trace_request(_attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let mut input = parse_macro_input!(input as ItemFn);
|
||||
let body_block = input.block;
|
||||
let fn_name = &input.sig.ident;
|
||||
|
||||
let token_stream = quote! {
|
||||
{
|
||||
use tracing::Instrument;
|
||||
|
||||
fn get_status<T>(res: &Result<T, HttpError>) -> http::StatusCode where T: dropshot::HttpCodedResponse {
|
||||
match res {
|
||||
Ok(_) => T::STATUS_CODE,
|
||||
Err(err) => err.status_code.as_status(),
|
||||
}
|
||||
}
|
||||
|
||||
let request_id = &rqctx.request_id;
|
||||
let req = &rqctx.request;
|
||||
|
||||
async {
|
||||
let result = async #body_block.await;
|
||||
let status = get_status(&result);
|
||||
|
||||
let span = tracing::Span::current();
|
||||
span.record("http.status", &status.as_str());
|
||||
if let Err(err) = &result {
|
||||
span.record("error.external", &err.external_message);
|
||||
span.record("error.internal", &err.internal_message);
|
||||
}
|
||||
|
||||
result
|
||||
}.instrument(
|
||||
tracing::info_span!(
|
||||
stringify!(handler.#fn_name),
|
||||
"request.id" = request_id,
|
||||
"http.method" = req.method().as_str(),
|
||||
"http.uri" = req.uri().to_string(),
|
||||
"http.status" = tracing::field::Empty,
|
||||
"error.external" = tracing::field::Empty,
|
||||
"error.internal" = tracing::field::Empty
|
||||
)
|
||||
).await
|
||||
}
|
||||
};
|
||||
let wrapped_body_block: TokenStream = token_stream.into();
|
||||
|
||||
input.block = Box::new(parse_macro_input!(wrapped_body_block as Block));
|
||||
|
||||
quote! {
|
||||
#input
|
||||
}
|
||||
.into()
|
||||
}
|
Loading…
Add table
Reference in a new issue