Skip to content

Commit

Permalink
Wrap detect with tracing
Browse files Browse the repository at this point in the history
  • Loading branch information
joshwlewis committed Oct 26, 2023
1 parent 8cef1ed commit e2fa9b8
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 9 deletions.
2 changes: 2 additions & 0 deletions libcnb/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ cyclonedx-bom = { version = "0.4.0", optional = true }
libcnb-common.workspace = true
libcnb-data.workspace = true
libcnb-proc-macros.workspace = true
opentelemetry = "0.20.0"
opentelemetry-stdout = { version = "0.1.0", features = ["trace"] }
serde = { version = "1.0.188", features = ["derive"] }
thiserror = "1.0.48"
toml.workspace = true
Expand Down
1 change: 1 addition & 0 deletions libcnb/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ mod error;
mod exit_code;
mod platform;
mod runtime;
mod tracing;
mod util;

pub use buildpack::Buildpack;
Expand Down
42 changes: 33 additions & 9 deletions libcnb/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@ use crate::detect::{DetectContext, InnerDetectResult};
use crate::error::Error;
use crate::platform::Platform;
use crate::sbom::cnb_sbom_path;
use crate::tracing::{set_buildpack_span_attributes, with_tracing};
use crate::util::is_not_found_error_kind;
use crate::{exit_code, TomlFileError, LIBCNB_SUPPORTED_BUILDPACK_API};
use libcnb_common::toml_file::{read_toml_file, write_toml_file};
use libcnb_data::store::Store;
use opentelemetry::global::{self, shutdown_tracer_provider, tracer};
use opentelemetry::trace::{Span, TraceContextExt, Tracer};
use opentelemetry::KeyValue;
use serde::de::DeserializeOwned;
use serde::Deserialize;
use std::ffi::OsStr;
Expand Down Expand Up @@ -138,17 +142,37 @@ pub fn libcnb_runtime_detect<B: Buildpack>(
buildpack_descriptor: read_buildpack_descriptor()?,
};

match buildpack.detect(detect_context)?.0 {
InnerDetectResult::Fail => Ok(exit_code::DETECT_DETECTION_FAILED),
InnerDetectResult::Pass { build_plan } => {
if let Some(build_plan) = build_plan {
write_toml_file(&build_plan, build_plan_path)
.map_err(Error::CannotWriteBuildPlan)?;
with_tracing(
"detect",
detect_context.buildpack_descriptor.buildpack.id.clone(),
|trace_ctx| {
let span = trace_ctx.span();
set_buildpack_span_attributes::<B>(&span, &detect_context.buildpack_descriptor);
let detect_result = buildpack.detect(detect_context);
if let Err(err) = detect_result {
span.record_error(&err);
span.set_status(opentelemetry::trace::Status::Error {
description: std::borrow::Cow::Borrowed("detect error"),
});
return Err(err);
}

Ok(exit_code::DETECT_DETECTION_PASSED)
}
}
match detect_result.unwrap().0 {
InnerDetectResult::Fail => {
span.add_event("detect-fail", vec![]);
Ok(exit_code::DETECT_DETECTION_FAILED)
}
InnerDetectResult::Pass { build_plan } => {
if let Some(build_plan) = build_plan {
write_toml_file(&build_plan, build_plan_path)
.map_err(Error::CannotWriteBuildPlan)?;
}
span.add_event("detect-pass", vec![]);
Ok(exit_code::DETECT_DETECTION_PASSED)
}
}
},
)
}

/// Build entry point for this framework.
Expand Down
80 changes: 80 additions & 0 deletions libcnb/src/tracing.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use crate::Buildpack;
use libcnb_data::buildpack::{BuildpackId, ComponentBuildpackDescriptor};
use opentelemetry::{
global::{self},
sdk::trace::TracerProvider,
trace::{SpanRef, Tracer, TracerProvider as TracerProviderImpl},
Context, KeyValue,
};
use opentelemetry_stdout::SpanExporter;
use std::{
fmt::Display,
fs::{create_dir_all, File},
io::sink,
path::Path,
};

pub fn with_tracing<F, R, S>(step: S, bp_id: BuildpackId, f: F) -> R
where
F: FnOnce(Context) -> R,
S: Display,
{
let bp_slug = bp_id.replace(['/', '.'], "_");
let provider = init_tracing(&bp_slug);
global::set_tracer_provider(provider.clone());
let tracer = provider.versioned_tracer(
option_env!("CARGO_PKG_NAME").unwrap_or("libcnb"),
option_env!("CARGO_PKG_VERSION"),
None as Option<&str>,
None,
);
let result = tracer.in_span(format!("libcnb-{step}-{bp_slug}"), |trace_ctx| f(trace_ctx));
provider.force_flush();
global::shutdown_tracer_provider();
result
}

fn init_tracing(bp_id: &str) -> TracerProvider {
let tracing_file_path = Path::new("/tmp")
.join("cnb-telemetry")
.join(format!("{bp_id}.jsonl"));

// Ensure tracing file path parent exists by creating it.
if let Some(parent_dir) = tracing_file_path.parent() {
let _ = create_dir_all(parent_dir);
}
let exporter = match File::options()
.create(true)
.append(true)
.open(&tracing_file_path)
{
Ok(file) => SpanExporter::builder().with_writer(file).build(),
Err(_) => SpanExporter::builder().with_writer(sink()).build(),
};

TracerProvider::builder()
.with_simple_exporter(exporter)
.build()
}

pub fn set_buildpack_span_attributes<B: Buildpack + ?Sized>(
span: &SpanRef,
bp_descriptor: &ComponentBuildpackDescriptor<B::Metadata>,
) {
span.set_attributes(vec![
KeyValue::new("buildpack_id", bp_descriptor.buildpack.id.to_string()),
KeyValue::new(
"buildpack_version",
bp_descriptor.buildpack.version.to_string(),
),
KeyValue::new(
"buildpack_name",
bp_descriptor
.buildpack
.name
.clone()
.unwrap_or_else(String::new),
),
KeyValue::new("buildpack_api", bp_descriptor.api.to_string()),
]);
}

0 comments on commit e2fa9b8

Please sign in to comment.