Skip to content

Commit 1b478d5

Browse files
feat: user project telemetry (#1961)
* wip: work in progress * chore: segment new tracing setup behavior behind new feature flag * chore: add `ProjectTelemetryConfig` variant to `ResourceTypeBeta` enum * revert: revert addition of sqlx traits for ResourceTypeBeta * chore: derive strum::AsRefStr for ResourceTypeBeta * style: maintain cargo's naming convention * refactor: don't attach OTLP exporter when OTEL_EXPORTER_OTLP_ENDPOINT env var is not set * style: rustfmt * chore(deps): remove unused dependencies and unnecessary features * style: clippy fix * chore: tighten pinned versions of opentelemetry crates * chore: add note about pinned `opentelemetry_sdk` version * chore: disable trace sampler configuration customizations
1 parent 45a5e0d commit 1b478d5

File tree

10 files changed

+941
-201
lines changed

10 files changed

+941
-201
lines changed

Cargo.lock

Lines changed: 325 additions & 159 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ opentelemetry = "0.21.0"
7171
opentelemetry_sdk = { version = "0.21.0", features = ["rt-tokio", "logs"] }
7272
opentelemetry-http = "0.10.0"
7373
opentelemetry-otlp = { version = "0.14.0", features = ["logs", "http-proto", "reqwest-client", "reqwest-rustls"] }
74-
opentelemetry-proto = "0.4.0"
7574
opentelemetry-contrib = { version = "0.4.0", features = ["datadog"] }
7675
opentelemetry-appender-tracing = "0.2.0"
7776
percent-encoding = "2.2"
@@ -99,7 +98,6 @@ tokio-stream = "0.1.11"
9998
tokio-tungstenite = { version = "0.20.1", features = [
10099
"rustls-tls-webpki-roots",
101100
] }
102-
tokio-util = "0.7.10"
103101
toml = "0.8.2"
104102
toml_edit = "0.20.2"
105103
tonic = "0.10.2"

codegen/src/shuttle_main.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,28 @@ pub(crate) fn tokens(_attr: TokenStream, item: TokenStream) -> TokenStream {
1212
let mut user_main_fn = parse_macro_input!(item as ItemFn);
1313
let loader_runner = LoaderAndRunner::from_item_fn(&mut user_main_fn);
1414

15-
quote! {
15+
Into::into(quote! {
1616
fn main() {
1717
// manual expansion of #[tokio::main]
1818
::shuttle_runtime::tokio::runtime::Builder::new_multi_thread()
1919
.enable_all()
2020
.build()
2121
.unwrap()
2222
.block_on(async {
23-
::shuttle_runtime::__internals::start(__loader, __runner).await;
23+
::shuttle_runtime::__internals::start(
24+
__loader,
25+
__runner,
26+
env!("CARGO_CRATE_NAME"),
27+
env!("CARGO_PKG_VERSION"),
28+
)
29+
.await;
2430
})
2531
}
2632

2733
#loader_runner
2834

2935
#user_main_fn
30-
}
31-
.into()
36+
})
3237
}
3338

3439
struct LoaderAndRunner {
@@ -358,7 +363,7 @@ mod tests {
358363
assert_eq!(actual.fn_inputs, expected_inputs);
359364

360365
// Make sure attributes was removed from input
361-
if let syn::FnArg::Typed(param) = input.sig.inputs.first().unwrap() {
366+
if let FnArg::Typed(param) = input.sig.inputs.first().unwrap() {
362367
assert!(
363368
param.attrs.is_empty(),
364369
"some attributes were not removed: {:?}",

common/src/resource.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,16 @@ pub enum Type {
165165
}
166166

167167
#[derive(
168-
Clone, Copy, Debug, strum::EnumString, strum::Display, Deserialize, Serialize, Eq, PartialEq,
168+
Clone,
169+
Copy,
170+
Debug,
171+
Deserialize,
172+
Eq,
173+
PartialEq,
174+
Serialize,
175+
strum::AsRefStr,
176+
strum::EnumString,
177+
strum::Display,
169178
)]
170179
#[typeshare::typeshare]
171180
// is a flat enum instead of nested enum to allow typeshare
@@ -343,7 +352,7 @@ mod test {
343352
];
344353

345354
for input in inputs {
346-
let actual = ResourceTypeBeta::from_str(&input.to_string()).unwrap();
355+
let actual = ResourceTypeBeta::from_str(input.as_ref()).unwrap();
347356
assert_eq!(input, actual, ":{} should map back to itself", input);
348357
}
349358
}

runtime/Cargo.toml

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,27 +19,68 @@ shuttle-service = { workspace = true }
1919
anyhow = { workspace = true }
2020
async-trait = { workspace = true }
2121
hyper = { workspace = true, features = ["http1", "server", "tcp"] }
22+
log = { version = "0.4", optional = true, default-features = false }
23+
opentelemetry = { version = "0.27.0", optional = true, default-features = false, features = ["logs", "metrics", "trace", "tracing"] }
24+
opentelemetry-otlp = { version = "0.27.0", optional = true, default-features = false, features = [
25+
"http-proto",
26+
"logs",
27+
"metrics",
28+
"reqwest-client",
29+
"trace",
30+
] }
31+
# NOTE: If the version of `opentelemetry_sdk` is changed/updated, remember up update the
32+
# `telemetry.sdk.version` value in `src/trace.rs:373`
33+
opentelemetry_sdk = { version = "=0.27.1", optional = true, default-features = false, features = [
34+
"http",
35+
"logs",
36+
"metrics",
37+
"rt-tokio",
38+
"trace",
39+
"spec_unstable_logs_enabled",
40+
] }
41+
opentelemetry-semantic-conventions = { version = "0.27.0", optional = true, default-features = false, features = ["semconv_experimental"] }
2242
serde = { workspace = true }
2343
serde_json = { workspace = true }
2444
strfmt = { workspace = true }
2545
tokio = { workspace = true, features = ["full"] }
26-
tokio-util = { workspace = true }
2746
tokio-stream = { workspace = true }
2847
tonic = { workspace = true }
29-
tracing = { workspace = true }
30-
tracing-subscriber = { workspace = true, optional = true }
48+
tracing = { workspace = true, features = ["attributes", "std"] }
49+
tracing-core = { version = "0.1", optional = true, default-features = false, features = ["std"] }
50+
tracing-log = { version = "0.2", optional = true, default-features = false, features = ["log-tracer", "std"] }
51+
tracing-opentelemetry = { version = "0.28.0", optional = true, default-features = false, features = ["metrics"] }
52+
tracing-subscriber = { workspace = true, optional = true, default-features = false }
3153

3254
[dev-dependencies]
3355
portpicker = { workspace = true }
3456
shuttle-service = { workspace = true, features = ["builder", "runner"] }
3557
shuttle-proto = { workspace = true, features = ["provisioner"] }
36-
uuid = { workspace = true }
3758

3859
[features]
3960
default = ["setup-tracing"]
4061
api-client-tracing = ["shuttle-api-client/tracing"]
4162

4263
setup-tracing = [
43-
"tracing-subscriber/default",
64+
"tracing-subscriber/ansi",
4465
"tracing-subscriber/env-filter",
66+
"tracing-subscriber/fmt",
67+
"tracing-subscriber/smallvec",
68+
"tracing-subscriber/std",
69+
"tracing-subscriber/tracing-log",
70+
]
71+
setup-telemetry = [
72+
"setup-tracing",
73+
"dep:log",
74+
"dep:opentelemetry",
75+
"dep:opentelemetry-otlp",
76+
"dep:opentelemetry_sdk",
77+
"dep:opentelemetry-semantic-conventions",
78+
"dep:tracing-core",
79+
"dep:tracing-log",
80+
"dep:tracing-opentelemetry",
81+
"tracing-subscriber/alloc",
82+
"tracing-subscriber/parking_lot",
83+
"tracing-subscriber/registry",
84+
"tracing-subscriber/tracing",
85+
"tracing-subscriber/tracing-serde",
4586
]

runtime/src/alpha.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ where
118118
}
119119
},
120120
Err(error) => {
121-
if error.is_panic() {
121+
return if error.is_panic() {
122122
let panic = error.into_panic();
123123
let msg = match panic.downcast_ref::<String>() {
124124
Some(msg) => msg.to_string(),
@@ -128,18 +128,18 @@ where
128128
},
129129
};
130130
println!("loading service panicked: {msg}");
131-
return Ok(Response::new(LoadResponse {
131+
Ok(Response::new(LoadResponse {
132132
success: false,
133133
message: msg,
134134
resources: vec![],
135-
}));
135+
}))
136136
} else {
137137
println!("loading service crashed: {error:#}");
138-
return Ok(Response::new(LoadResponse {
138+
Ok(Response::new(LoadResponse {
139139
success: false,
140140
message: error.to_string(),
141141
resources: vec![],
142-
}));
142+
}))
143143
}
144144
}
145145
};
@@ -214,7 +214,7 @@ where
214214

215215
println!("Starting on {service_address}");
216216

217-
let (kill_tx, kill_rx) = tokio::sync::oneshot::channel();
217+
let (kill_tx, kill_rx) = oneshot::channel();
218218
*self.kill_tx.lock().unwrap() = Some(kill_tx);
219219

220220
let handle = tokio::runtime::Handle::current();
@@ -296,7 +296,7 @@ where
296296
} else {
297297
println!("failed to stop deployment");
298298

299-
Ok(tonic::Response::new(StopResponse { success: false }))
299+
Ok(Response::new(StopResponse { success: false }))
300300
}
301301
}
302302

@@ -324,7 +324,7 @@ where
324324
Ok(Response::new(ReceiverStream::new(rx)))
325325
}
326326

327-
async fn version(&self, _requset: Request<Ping>) -> Result<Response<VersionInfo>, Status> {
327+
async fn version(&self, _request: Request<Ping>) -> Result<Response<VersionInfo>, Status> {
328328
Ok(Response::new(VersionInfo {
329329
version: crate::VERSION_STRING.to_owned(),
330330
}))

runtime/src/lib.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ mod plugins;
1212
mod rt;
1313
mod start;
1414

15+
#[cfg(feature = "setup-telemetry")]
16+
mod trace;
17+
1518
// Public API
1619
pub use plugins::{Metadata, Secrets};
1720
pub use shuttle_codegen::main;
@@ -51,7 +54,7 @@ pub mod __internals {
5154
O: Future<Output = Result<Vec<Vec<u8>>, Error>> + Send,
5255
{
5356
async fn load(self, factory: ResourceFactory) -> Result<Vec<Vec<u8>>, Error> {
54-
(self)(factory).await
57+
self(factory).await
5558
}
5659
}
5760

@@ -72,7 +75,7 @@ pub mod __internals {
7275
type Service = S;
7376

7477
async fn run(self, resources: Vec<Vec<u8>>) -> Result<Self::Service, Error> {
75-
(self)(resources).await
78+
self(resources).await
7679
}
7780
}
7881
}

runtime/src/rt.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ pub async fn start(loader: impl Loader + Send + 'static, runner: impl Runner + S
9393
// light hyper server
9494
let make_service = make_service_fn(|_conn| async {
9595
Ok::<_, Infallible>(service_fn(|_req| async move {
96-
trace!("Receivied health check");
96+
trace!("Received health check");
9797
// TODO: A hook into the `Service` trait can be added here
9898
trace!("Responding to health check");
9999
Result::<Response<Body>, hyper::Error>::Ok(Response::new(Body::empty()))
@@ -130,7 +130,7 @@ pub async fn start(loader: impl Loader + Send + 'static, runner: impl Runner + S
130130
// Sort secrets by key
131131
let secrets = BTreeMap::from_iter(secrets.into_iter().map(|(k, v)| (k, Secret::new(v))));
132132

133-
// TODO: rework resourcefactory
133+
// TODO: rework `ResourceFactory`
134134
let factory = ResourceFactory::new(project_name, secrets.clone(), env);
135135
let mut resources = match loader.load(factory).await {
136136
Ok(r) => r,

runtime/src/start.rs

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,25 @@ impl Args {
4848
}
4949
}
5050

51-
pub async fn start(loader: impl Loader + Send + 'static, runner: impl Runner + Send + 'static) {
51+
pub async fn start(
52+
loader: impl Loader + Send + 'static,
53+
runner: impl Runner + Send + 'static,
54+
#[cfg_attr(not(feature = "setup-telemetry"), allow(unused_variables))] crate_name: &'static str,
55+
#[cfg_attr(not(feature = "setup-telemetry"), allow(unused_variables))]
56+
package_version: &'static str,
57+
) {
5258
// `--version` overrides any other arguments. Used by cargo-shuttle to check compatibility on local runs.
5359
if std::env::args().any(|arg| arg == "--version") {
5460
println!("{}", crate::VERSION_STRING);
5561
return;
5662
}
5763

58-
println!("{} starting", crate::VERSION_STRING);
64+
println!(
65+
"{} starting: {} {}",
66+
crate::VERSION_STRING,
67+
crate_name,
68+
package_version
69+
);
5970

6071
let args = match Args::parse() {
6172
Ok(args) => args,
@@ -69,33 +80,41 @@ pub async fn start(loader: impl Loader + Send + 'static, runner: impl Runner + S
6980
};
7081

7182
// this is handled after arg parsing to not interfere with --version above
72-
#[cfg(feature = "setup-tracing")]
83+
#[cfg(all(feature = "setup-tracing", not(feature = "setup-telemetry")))]
7384
{
7485
use tracing_subscriber::{fmt, prelude::*, registry, EnvFilter};
7586
registry()
7687
.with(fmt::layer().without_time())
7788
.with(
7889
// let user override RUST_LOG in local run if they want to
79-
EnvFilter::try_from_default_env()
90+
EnvFilter::try_from_default_env().unwrap_or_else(|_| {
8091
// otherwise use our default
81-
.or_else(|_| {
82-
EnvFilter::try_new(if args.beta {
92+
Into::into(format!(
93+
"{},{}=debug",
94+
if args.beta {
8395
"info"
8496
} else {
8597
"info,shuttle=trace"
86-
})
87-
})
88-
.unwrap(),
98+
},
99+
crate_name
100+
))
101+
}),
89102
)
90103
.init();
104+
}
91105

92-
if args.beta {
93-
tracing::warn!(
94-
"Default tracing subscriber initialized (https://docs.shuttle.dev/docs/logs)"
95-
);
96-
} else {
97-
tracing::warn!("Default tracing subscriber initialized (https://docs.shuttle.rs/configuration/logs)");
98-
}
106+
#[cfg(feature = "setup-telemetry")]
107+
let _guard = crate::trace::init_tracing_subscriber(crate_name, package_version);
108+
109+
#[cfg(any(feature = "setup-tracing", feature = "setup-telemetry"))]
110+
if args.beta {
111+
tracing::warn!(
112+
"Default tracing subscriber initialized (https://docs.shuttle.dev/docs/logs)"
113+
);
114+
} else {
115+
tracing::warn!(
116+
"Default tracing subscriber initialized (https://docs.shuttle.rs/configuration/logs)"
117+
);
99118
}
100119

101120
if args.beta {

0 commit comments

Comments
 (0)