Added Telemetry

closes #8
This commit is contained in:
brotoskyj
2026-01-15 14:32:28 -05:00
parent 0ae38b0e01
commit 6169e6065d
6 changed files with 492 additions and 19 deletions
+121 -15
View File
@@ -1,6 +1,14 @@
use modules::*;
use opentelemetry::KeyValue;
use opentelemetry::global;
use opentelemetry::global::ObjectSafeSpan;
use opentelemetry::trace::SpanKind;
use opentelemetry::trace::Status;
use opentelemetry::trace::TraceContextExt;
use opentelemetry::trace::Tracer;
use serenity::all::ChannelId;
use serenity::async_trait;
use serenity::futures::channel::oneshot::channel;
use serenity::model::channel::Message;
use serenity::model::gateway::Ready;
use serenity::prelude::*;
@@ -32,13 +40,50 @@ impl EventHandler for Handler {
println!("Error sending message: {why:?}");
}
if msg.content == "!join" {
let tracer = global::tracer("RhythmWorks");
let span = tracer.start("Join Message Received");
let cx = opentelemetry::Context::current_with_span(span);
let guild_id = match msg.guild_id {
Some(g) => g,
None => return,
};
let channel_id = match get_user_voice_channel(&ctx, &msg) {
Some(c) => c,
Some(g) => {
cx.span().add_event(
"Received Guild ID",
vec![KeyValue::new("Server ID", g.to_string())],
);
cx.span().set_status(opentelemetry::trace::Status::Ok);
cx.span()
.set_attribute(KeyValue::new("Guild_ID", g.to_string()));
g
}
None => {
cx.span().add_event(
"Failed to Retreive Guild ID",
vec![KeyValue::new("Server ID", "None")],
);
cx.span()
.set_status(opentelemetry::trace::Status::error("Failed"));
return;
}
};
let channel_id = match get_user_voice_channel(&ctx, &msg) {
Some(c) => {
cx.span().add_event(
"Received Channel ID",
vec![KeyValue::new("Channel ID", c.to_string())],
);
cx.span().set_status(Status::Ok);
c
}
None => {
cx.span().add_event(
"Failed to Retreive Channel ID",
vec![KeyValue::new("Channel ID", "None")],
);
cx.span()
.set_status(opentelemetry::trace::Status::error(format!(
"{} not in Voice Channel",
msg.author.to_string()
)));
let _ = msg
.channel_id
.say(&ctx.http, "You must be in a voice channel")
@@ -46,7 +91,6 @@ impl EventHandler for Handler {
return;
}
};
let manager = get(&ctx).await.expect("Songbird not initialized").clone();
let _ = manager.join(guild_id, channel_id).await;
@@ -55,6 +99,11 @@ impl EventHandler for Handler {
.channel_id
.say(&ctx.http, "Joined your voice channel!")
.await;
cx.span().add_event(
"Joined Voice Channel",
vec![KeyValue::new("Voice Channel", msg.channel_id.to_string())],
);
cx.span().set_status(Status::Ok);
}
if msg.content == "!leave" {
let guild_id = match msg.guild_id {
@@ -71,6 +120,8 @@ impl EventHandler for Handler {
}
}
if msg.content.starts_with("!play") {
let tracer = global::tracer("RhythmWorks");
let span = tracer.start("Play Message Received");
let mut yt_url = msg
.content
.strip_prefix("!play ")
@@ -84,7 +135,30 @@ impl EventHandler for Handler {
let _ = msg.reply(&ctx, "Please provide a YouTube URL.").await;
return;
}
let guild_id = msg.guild_id.unwrap();
let cx = opentelemetry::Context::current_with_span(span);
cx.span()
.set_attribute(KeyValue::new("Youtube_URL", yt_url.to_string()));
let guild_id = match msg.guild_id {
Some(g) => {
cx.span().add_event(
"Received Guild ID",
vec![KeyValue::new("Server ID", g.to_string())],
);
cx.span().set_status(opentelemetry::trace::Status::Ok);
cx.span()
.set_attribute(KeyValue::new("Guild_ID", g.to_string()));
g
}
None => {
cx.span().add_event(
"Failed to Retreive Guild ID",
vec![KeyValue::new("Server ID", "None")],
);
cx.span()
.set_status(opentelemetry::trace::Status::error("Failed"));
return;
}
};
let manager = songbird::get(&ctx).await.unwrap().clone();
let handler_lock = if let Some(call) = manager.get(guild_id) {
call
@@ -92,21 +166,46 @@ impl EventHandler for Handler {
let channel_id = match get_user_voice_channel(&ctx, &msg) {
Some(c) => c,
None => {
let _ = msg.reply(&ctx, "Join a voice channel first!").await;
cx.span().add_event(
"Failed to Retreive Channel ID",
vec![KeyValue::new("Channel ID", "None")],
);
cx.span()
.set_status(opentelemetry::trace::Status::error(format!(
"{} not in Voice Channel",
msg.author.to_string()
)));
let _ = msg
.channel_id
.say(&ctx.http, "You must be in a voice channel")
.await;
return;
}
};
manager.join(guild_id, channel_id).await.unwrap()
};
let output = Command::new("./yt-dlp")
let output = match Command::new("./yt-dlp")
.args(["-f", "bestaudio", "-g", &yt_url])
.stdout(Stdio::piped())
.output()
.expect("yt-dlp failed");
if !output.status.success() {
let _ = msg.reply(&ctx, "Failed to fetch audio stream.").await;
return;
}
{
Ok(output) => {
cx.span().add_event(
"Retreiving Youtube Information",
vec![KeyValue::new("Success", yt_url.to_string())],
);
output
}
Err(e) => {
cx.span().add_event(
"Retreiving Youtube Information",
vec![KeyValue::new("Failed", e.to_string())],
);
cx.span().set_status(Status::error("Failed"));
eprintln!("{}", e);
return;
}
};
let stream_url = String::from_utf8(output.stdout)
.expect("Invalid UTF-8")
.trim()
@@ -116,8 +215,10 @@ impl EventHandler for Handler {
let _ = call.enqueue_input(input).await;
let position = call.queue().len();
let response = if position == 1 {
cx.span().add_event("Starting Playback", vec![KeyValue::new("Status", "Playing".to_string())]);
"🎶 Now playing!".to_string()
} else {
cx.span().add_event("Starting Playback", vec![KeyValue::new("Status", "Added to Queue".to_string())]);
format!("🎶 Added Song to Queue: #{}", position)
};
let _ = msg.channel_id.say(&ctx.http, response).await;
@@ -180,7 +281,12 @@ async fn main() {
This program comes with ABSOLUTELY NO WARRANTY\n
This is free software, and you are welcome to redistribute it under certain conditions."
);
updator::update().await;
let tracer_provider = telemetry::init_telemetry();
global::set_tracer_provider(tracer_provider.clone());
let tracer: global::BoxedTracer = global::tracer("tracer");
tracer
.in_span("Checking for Updates", |cx| updator::update())
.await;
println!("Please paste in your bot token");
let mut input = String::new();
io::stdin()
+1
View File
@@ -1 +1,2 @@
pub mod updator;
pub mod telemetry;
+26
View File
@@ -0,0 +1,26 @@
use opentelemetry::KeyValue;
use opentelemetry_otlp::{WithExportConfig, WithTonicConfig};
use opentelemetry_sdk::{Resource, runtime};
use tonic::transport::{Channel, ClientTlsConfig};
pub fn init_telemetry() -> opentelemetry_sdk::trace::TracerProvider {
let endpoint = "https://signoz.racooncity.org".to_string();
let channel = Channel::from_shared(endpoint.clone())
.unwrap()
.tls_config(ClientTlsConfig::new().with_native_roots())
.unwrap()
.connect_lazy();
let exporter = opentelemetry_otlp::SpanExporter::builder()
.with_tonic()
.with_endpoint(endpoint.clone())
.with_channel(channel)
.build()
.expect("Failed to Build Exporter");
opentelemetry_sdk::trace::TracerProvider::builder()
.with_batch_exporter(exporter, runtime::Tokio)
.with_resource(Resource::new(vec![KeyValue::new(
"service.name",
"RhythmWorks",
)]))
.build()
}