A decentralized music tracking and discovery platform built on AT Protocol 🎵

Refactor logging to use `tracing` instead of `println` and `eprintln`

- Replaced all instances of `println!` and `eprintln!` with `tracing::info!`, `tracing::warn!`, and `tracing::error!` for better structured logging.
- Updated log messages to include relevant context and structured fields for improved traceability.
- Ensured consistent logging practices across the `jetstream`, `scrobbler`, and `webscrobbler` crates.

+260 -426
+44 -42
crates/analytics/src/subscriber/mod.rs
··· 42 42 let data = String::from_utf8(msg.payload.to_vec()).unwrap(); 43 43 match serde_json::from_str::<ScrobblePayload>(&data) { 44 44 Ok(payload) => match save_scrobble(conn.clone(), payload.clone()).await { 45 - Ok(_) => println!( 46 - "Scrobble saved successfully for {}", 47 - payload.scrobble.uri.cyan() 45 + Ok(_) => tracing::info!( 46 + uri = %payload.scrobble.uri.cyan(), 47 + "Scrobble saved successfully", 48 48 ), 49 - Err(e) => eprintln!("Error saving scrobble: {}", e), 49 + Err(e) => tracing::error!("Error saving scrobble: {}", e), 50 50 }, 51 51 Err(e) => { 52 - eprintln!("Error parsing payload: {}", e); 53 - println!("{}", data); 52 + tracing::error!("Error parsing payload: {}", e); 53 + tracing::debug!("{}", data); 54 54 } 55 55 } 56 56 } ··· 77 77 match serde_json::from_str::<NewTrackPayload>(&data) { 78 78 Ok(payload) => match save_track(conn.clone(), payload.clone()).await { 79 79 Ok(_) => { 80 - println!("Song saved successfully for {}", payload.track.title.cyan()) 80 + tracing::info!( 81 + title = %payload.track.title.cyan(), 82 + "Track saved successfully", 83 + ) 81 84 } 82 - Err(e) => eprintln!("Error saving song: {}", e), 85 + Err(e) => tracing::error!("Error saving track: {}", e), 83 86 }, 84 87 Err(e) => { 85 - eprintln!("Error parsing payload: {}", e); 86 - println!("{}", data); 88 + tracing::error!("Error parsing payload: {}", e); 89 + tracing::debug!("{}", data); 87 90 } 88 91 } 89 92 } ··· 109 112 let data = String::from_utf8(msg.payload.to_vec()).unwrap(); 110 113 match serde_json::from_str::<LikePayload>(&data) { 111 114 Ok(payload) => match like(conn.clone(), payload.clone()).await { 112 - Ok(_) => println!( 113 - "Like saved successfully for {}", 114 - payload.track_id.xata_id.cyan() 115 + Ok(_) => tracing::info!( 116 + track_id = %payload.track_id.xata_id.cyan(), 117 + "Like saved successfully", 115 118 ), 116 - Err(e) => eprintln!("Error saving like: {}", e), 119 + Err(e) => tracing::error!("Error saving like: {}", e), 117 120 }, 118 121 Err(e) => { 119 - eprintln!("Error parsing payload: {}", e); 120 - println!("{}", data); 122 + tracing::error!("Error parsing payload: {}", e); 123 + tracing::debug!("{}", data); 121 124 } 122 125 } 123 126 } ··· 143 146 let data = String::from_utf8(msg.payload.to_vec()).unwrap(); 144 147 match serde_json::from_str::<UnlikePayload>(&data) { 145 148 Ok(payload) => match unlike(conn.clone(), payload.clone()).await { 146 - Ok(_) => println!( 147 - "Unlike saved successfully for {}", 148 - payload.track_id.xata_id.cyan() 149 + Ok(_) => tracing::info!( 150 + track_id = %payload.track_id.xata_id.cyan(), 151 + "Unlike saved successfully", 149 152 ), 150 - Err(e) => eprintln!("Error saving unlike: {}", e), 153 + Err(e) => tracing::error!("Error saving unlike: {}", e), 151 154 }, 152 155 Err(e) => { 153 - eprintln!("Error parsing payload: {}", e); 154 - println!("{}", data); 156 + tracing::error!("Error parsing payload: {}", e); 157 + tracing::debug!("{}", data); 155 158 } 156 159 } 157 160 } ··· 177 180 let data = String::from_utf8(msg.payload.to_vec()).unwrap(); 178 181 match serde_json::from_str::<UserPayload>(&data) { 179 182 Ok(payload) => match save_user(conn.clone(), payload.clone()).await { 180 - Ok(_) => println!( 181 - "User saved successfully for {}{}", 182 - "@".cyan(), 183 - payload.handle.cyan() 183 + Ok(_) => tracing::info!( 184 + handle = %payload.handle.cyan(), 185 + "User saved successfully", 184 186 ), 185 - Err(e) => eprintln!("Error saving user: {}", e), 187 + Err(e) => tracing::error!("Error saving user: {}", e), 186 188 }, 187 189 Err(e) => { 188 - eprintln!("Error parsing payload: {}", e); 189 - println!("{}", data); 190 + tracing::error!("Error parsing payload: {}", e); 191 + tracing::debug!("{}", data); 190 192 } 191 193 } 192 194 } ··· 253 255 Ok(_) => (), 254 256 Err(e) => { 255 257 if !e.to_string().contains("violates primary key constraint") { 256 - println!("[artists] error: {}", e); 258 + tracing::error!("[artists] error: {}", e); 257 259 return Err(e.into()); 258 260 } 259 261 } ··· 308 310 Ok(_) => (), 309 311 Err(e) => { 310 312 if !e.to_string().contains("violates primary key constraint") { 311 - println!("[albums] error: {}", e); 313 + tracing::error!("[albums] error: {}", e); 312 314 return Err(e.into()); 313 315 } 314 316 } ··· 371 373 Ok(_) => (), 372 374 Err(e) => { 373 375 if !e.to_string().contains("violates primary key constraint") { 374 - println!("[tracks] error: {}", e); 376 + tracing::error!("[tracks] error: {}", e); 375 377 return Err(e.into()); 376 378 } 377 379 } ··· 394 396 Ok(_) => (), 395 397 Err(e) => { 396 398 if !e.to_string().contains("violates primary key constraint") { 397 - println!("[album_tracks] error: {}", e); 399 + tracing::error!("[album_tracks] error: {}", e); 398 400 return Err(e.into()); 399 401 } 400 402 } ··· 412 414 Ok(_) => (), 413 415 Err(e) => { 414 416 if !e.to_string().contains("violates primary key constraint") { 415 - println!("[artist_tracks] error: {}", e); 417 + tracing::error!("[artist_tracks] error: {}", e); 416 418 return Err(e.into()); 417 419 } 418 420 } ··· 430 432 Ok(_) => (), 431 433 Err(e) => { 432 434 if !e.to_string().contains("violates primary key constraint") { 433 - println!("[artist_albums] error: {}", e); 435 + tracing::error!("[artist_albums] error: {}", e); 434 436 return Err(e.into()); 435 437 } 436 438 } ··· 448 450 Ok(_) => (), 449 451 Err(e) => { 450 452 if !e.to_string().contains("violates primary key constraint") { 451 - println!("[user_albums] error: {}", e); 453 + tracing::error!("[user_albums] error: {}", e); 452 454 return Err(e.into()); 453 455 } 454 456 } ··· 466 468 Ok(_) => (), 467 469 Err(e) => { 468 470 if !e.to_string().contains("violates primary key constraint") { 469 - println!("[user_artists] error: {}", e); 471 + tracing::error!("[user_artists] error: {}", e); 470 472 return Err(e.into()); 471 473 } 472 474 } ··· 484 486 Ok(_) => (), 485 487 Err(e) => { 486 488 if !e.to_string().contains("violates primary key constraint") { 487 - println!("[user_tracks] error: {}", e); 489 + tracing::error!("[user_tracks] error: {}", e); 488 490 return Err(e.into()); 489 491 } 490 492 } ··· 521 523 Ok(_) => (), 522 524 Err(e) => { 523 525 if !e.to_string().contains("violates primary key constraint") { 524 - println!("[scrobbles] error: {}", e); 526 + tracing::error!("[scrobbles] error: {}", e); 525 527 return Err(e.into()); 526 528 } 527 529 } ··· 593 595 Ok(_) => (), 594 596 Err(e) => { 595 597 if !e.to_string().contains("violates primary key constraint") { 596 - println!("[tracks] error: {}", e); 598 + tracing::error!("[tracks] error: {}", e); 597 599 return Err(e.into()); 598 600 } 599 601 } ··· 616 618 Ok(_) => (), 617 619 Err(e) => { 618 620 if !e.to_string().contains("violates primary key constraint") { 619 - println!("[album_tracks] error: {}", e); 621 + tracing::error!("[album_tracks] error: {}", e); 620 622 return Err(e.into()); 621 623 } 622 624 } ··· 634 636 Ok(_) => (), 635 637 Err(e) => { 636 638 if !e.to_string().contains("violates primary key constraint") { 637 - println!("[artist_tracks] error: {}", e); 639 + tracing::error!("[artist_tracks] error: {}", e); 638 640 return Err(e.into()); 639 641 } 640 642 }
+2 -2
crates/dropbox/src/cmd/serve.rs
··· 27 27 req: HttpRequest, 28 28 ) -> Result<impl Responder, actix_web::Error> { 29 29 let method = req.match_info().get("method").unwrap_or("unknown"); 30 - println!("Method: {}", method.bright_green()); 30 + tracing::info!(method = %method.bright_green(), "API call"); 31 31 32 32 let conn = data.get_ref().clone(); 33 33 handle(method, &mut payload, &req, conn) ··· 41 41 let addr = format!("{}:{}", host, port); 42 42 43 43 let url = format!("http://{}", addr); 44 - println!("Listening on {}", url.bright_green()); 44 + tracing::info!(url = %url.bright_green(), "Listening on"); 45 45 46 46 let pool = PgPoolOptions::new() 47 47 .max_connections(5)
+8
crates/dropbox/src/handlers/files.rs
··· 2 2 3 3 use actix_web::{web, HttpRequest, HttpResponse}; 4 4 use anyhow::Error; 5 + use owo_colors::OwoColorize; 5 6 use sqlx::{Pool, Postgres}; 6 7 use tokio_stream::StreamExt; 7 8 ··· 24 25 let body = read_payload!(payload); 25 26 let params = serde_json::from_slice::<GetFilesParams>(&body)?; 26 27 let refresh_token = find_dropbox_refresh_token(&pool.clone(), &params.did).await?; 28 + tracing::info!(did = %params.did.bright_green(), "dropbox.getFiles"); 27 29 28 30 if refresh_token.is_none() { 29 31 return Ok(HttpResponse::Unauthorized().finish()); ··· 48 50 let body = read_payload!(payload); 49 51 let params = serde_json::from_slice::<GetFilesParams>(&body)?; 50 52 let refresh_token = find_dropbox_refresh_token(&pool.clone(), &params.did).await?; 53 + tracing::info!(did = %params.did.bright_green(), "dropbox.createMusicFolder"); 51 54 52 55 if refresh_token.is_none() { 53 56 return Ok(HttpResponse::Unauthorized().finish()); ··· 72 75 let body = read_payload!(payload); 73 76 let params = serde_json::from_slice::<GetFilesAtParams>(&body)?; 74 77 let refresh_token = find_dropbox_refresh_token(&pool.clone(), &params.did).await?; 78 + tracing::info!(did = %params.did.bright_green(), path = %params.path.bright_green(), "dropbox.getFilesAt"); 75 79 76 80 if refresh_token.is_none() { 77 81 return Ok(HttpResponse::Unauthorized().finish()); ··· 96 100 let body = read_payload!(payload); 97 101 let params = serde_json::from_slice::<DownloadFileParams>(&body)?; 98 102 let refresh_token = find_dropbox_refresh_token(&pool.clone(), &params.did).await?; 103 + tracing::info!(did = %params.did.bright_green(), path = %params.path.bright_green(), "dropbox.downloadFile"); 99 104 100 105 if refresh_token.is_none() { 101 106 return Ok(HttpResponse::Unauthorized().finish()); ··· 118 123 let body = read_payload!(payload); 119 124 let params = serde_json::from_slice::<DownloadFileParams>(&body)?; 120 125 let refresh_token = find_dropbox_refresh_token(&pool.clone(), &params.did).await?; 126 + tracing::info!(did = %params.did.bright_green(), path = %params.path.bright_green(), "dropbox.getTemporaryLink"); 121 127 122 128 if refresh_token.is_none() { 123 129 return Ok(HttpResponse::Unauthorized().finish()); ··· 142 148 let body = read_payload!(payload); 143 149 let params = serde_json::from_slice::<DownloadFileParams>(&body)?; 144 150 let refresh_token = find_dropbox_refresh_token(&pool.clone(), &params.did).await?; 151 + tracing::info!(did = %params.did.bright_green(), path = %params.path.bright_green(), "dropbox.getMetadata"); 145 152 146 153 if refresh_token.is_none() { 147 154 return Ok(HttpResponse::Unauthorized().finish()); ··· 165 172 ) -> Result<HttpResponse, Error> { 166 173 let body = read_payload!(payload); 167 174 let params = serde_json::from_slice::<ScanFolderParams>(&body)?; 175 + tracing::info!(did = %params.did.bright_green(), path = %params.path.bright_green(), "dropbox.scanFolder"); 168 176 169 177 let pool = pool.clone(); 170 178 thread::spawn(move || {
+60 -74
crates/dropbox/src/scan.rs
··· 91 91 .await?; 92 92 93 93 if res.status().as_u16() == 400 || res.status().as_u16() == 409 { 94 - println!("Path not found: {}", path.bright_red()); 94 + tracing::error!(path = %path.bright_red(), "Path not found"); 95 95 return Ok(()); 96 96 } 97 97 98 98 let entry = res.json::<Entry>().await?; 99 99 100 100 if entry.tag.clone().unwrap().as_str() == "folder" { 101 - println!("Scanning folder: {}", path.bright_green()); 101 + tracing::info!(path = %path.bright_green(), "Scanning folder"); 102 102 103 103 let parent_path = Path::new(&path) 104 104 .parent() ··· 160 160 161 161 let client = Client::new(); 162 162 163 - println!("Downloading file: {}", path.bright_green()); 163 + tracing::info!(path = %path.bright_green(), "Downloading file"); 164 164 165 165 let res = client 166 166 .post(&format!("{}/files/download", CONTENT_URL)) ··· 176 176 let mut tmpfile = File::create(&tmppath)?; 177 177 tmpfile.write_all(&bytes)?; 178 178 179 - println!( 180 - "Reading file: {}", 181 - &tmppath.clone().display().to_string().bright_green() 182 - ); 179 + tracing::info!(path = %tmppath.clone().display().to_string().bright_green(), "Reading file"); 183 180 184 181 let tagged_file = match Probe::open(&tmppath)?.read() { 185 182 Ok(tagged_file) => tagged_file, 186 183 Err(e) => { 187 - println!("Error opening file: {}", e); 184 + tracing::error!(path = %tmppath.clone().display().to_string().bright_red(), "Error reading file: {}", e); 188 185 return Ok(()); 189 186 } 190 187 }; ··· 193 190 let tag = match primary_tag { 194 191 Some(tag) => tag, 195 192 None => { 196 - println!("No tag found in file"); 193 + tracing::error!(path = %tmppath.clone().display().to_string().bright_red(), "No tag found in file"); 197 194 return Ok(()); 198 195 } 199 196 }; 200 197 201 198 let pictures = tag.pictures(); 202 199 203 - println!( 204 - "Title: {}", 205 - tag.get_string(&lofty::tag::ItemKey::TrackTitle) 206 - .unwrap_or_default() 207 - .bright_green() 200 + tracing::info!( 201 + title = %tag 202 + .get_string(&lofty::tag::ItemKey::TrackTitle) 203 + .unwrap_or_default(), 208 204 ); 209 - println!( 210 - "Artist: {}", 211 - tag.get_string(&lofty::tag::ItemKey::TrackArtist) 212 - .unwrap_or_default() 213 - .bright_green() 205 + tracing::info!( 206 + artist = %tag 207 + .get_string(&lofty::tag::ItemKey::TrackArtist) 208 + .unwrap_or_default(), 214 209 ); 215 - println!( 216 - "Album Artist: {}", 217 - tag.get_string(&lofty::tag::ItemKey::AlbumArtist) 218 - .unwrap_or_default() 219 - .bright_green() 210 + tracing::info!( 211 + album = %tag 212 + .get_string(&lofty::tag::ItemKey::AlbumTitle) 213 + .unwrap_or_default(), 220 214 ); 221 - println!( 222 - "Album: {}", 223 - tag.get_string(&lofty::tag::ItemKey::AlbumTitle) 224 - .unwrap_or_default() 225 - .bright_green() 215 + tracing::info!( 216 + album_artist = %tag 217 + .get_string(&lofty::tag::ItemKey::AlbumArtist) 218 + .unwrap_or_default(), 226 219 ); 227 - println!( 228 - "Lyrics: {}", 229 - tag.get_string(&lofty::tag::ItemKey::Lyrics) 230 - .unwrap_or_default() 231 - .bright_green() 232 - ); 233 - println!("Year: {}", tag.year().unwrap_or_default().bright_green()); 234 - println!( 235 - "Track Number: {}", 236 - tag.track().unwrap_or_default().bright_green() 237 - ); 238 - println!( 239 - "Track Total: {}", 240 - tag.track_total().unwrap_or_default().bright_green() 220 + tracing::info!( 221 + lyrics = %tag 222 + .get_string(&lofty::tag::ItemKey::Lyrics) 223 + .unwrap_or_default(), 241 224 ); 242 - println!( 243 - "Release Date: {:?}", 244 - tag.get_string(&lofty::tag::ItemKey::OriginalReleaseDate) 245 - .unwrap_or_default() 246 - .bright_green() 225 + tracing::info!(year = %tag.year().unwrap_or_default()); 226 + tracing::info!(track_number = %tag.track().unwrap_or_default()); 227 + tracing::info!(track_total = %tag.track_total().unwrap_or_default()); 228 + tracing::info!( 229 + release_date = %tag 230 + .get_string(&lofty::tag::ItemKey::OriginalReleaseDate) 231 + .unwrap_or_default(), 247 232 ); 248 - println!( 249 - "Recording Date: {:?}", 250 - tag.get_string(&lofty::tag::ItemKey::RecordingDate) 251 - .unwrap_or_default() 252 - .bright_green() 233 + tracing::info!( 234 + recording_date = %tag 235 + .get_string(&lofty::tag::ItemKey::RecordingDate) 236 + .unwrap_or_default(), 253 237 ); 254 - println!( 255 - "Copyright Message: {}", 256 - tag.get_string(&lofty::tag::ItemKey::CopyrightMessage) 257 - .unwrap_or_default() 258 - .bright_green() 238 + tracing::info!( 239 + copyright_message = %tag 240 + .get_string(&lofty::tag::ItemKey::CopyrightMessage) 241 + .unwrap_or_default(), 259 242 ); 260 - println!("Pictures: {:?}", pictures); 243 + tracing::info!(pictures = ?pictures); 261 244 262 245 let title = tag 263 246 .get_string(&lofty::tag::ItemKey::TrackTitle) ··· 290 273 291 274 match track { 292 275 Some(track) => { 293 - println!("Track exists: {}", title.bright_green()); 276 + tracing::info!(title = %title.bright_green(), "Track exists"); 294 277 let parent_path = Path::new(&path) 295 278 .parent() 296 279 .map(|p| p.to_string_lossy().to_string()); 297 280 let status = 298 281 create_dropbox_path(&pool, &entry, &track, &dropbox_id, parent_path).await; 299 - println!("status: {:?}", status); 282 + tracing::info!(status = ?status); 300 283 301 284 // TODO: publish file metadata to nats 302 285 } 303 286 None => { 304 - println!("Creating track: {}", title.bright_green()); 287 + tracing::info!(title = %title.bright_green(), "Creating track"); 305 288 let album_art = 306 289 upload_album_cover(albumart_id.into(), pictures, &access_token).await?; 307 290 let client = Client::new(); ··· 338 321 })) 339 322 .send() 340 323 .await?; 341 - println!("Track Saved: {} {}", title, response.status()); 324 + tracing::info!(title = title, status = %response.status(), "Track saved"); 342 325 tokio::time::sleep(std::time::Duration::from_secs(3)).await; 343 326 344 327 let track = get_track_by_hash(&pool, &hash).await?; ··· 353 336 return Ok(()); 354 337 } 355 338 356 - println!("Failed to create track: {}", title.bright_green()); 339 + tracing::error!(title = %title.bright_red(), "Failed to create track"); 357 340 } 358 341 } 359 342 ··· 413 396 .send() 414 397 .await?; 415 398 416 - println!("Cover uploaded: {}", response.status()); 399 + tracing::info!(status = %response.status(), "Cover uploaded"); 417 400 418 401 Ok(Some(name)) 419 402 } ··· 433 416 let meta_opts = MetadataOptions::default(); 434 417 let format_opts = FormatOptions::default(); 435 418 436 - let probed = 437 - match symphonia::default::get_probe().format(&hint, media_source, &format_opts, &meta_opts) 438 - { 439 - Ok(probed) => probed, 440 - Err(_) => { 441 - println!("Error probing file"); 442 - return Ok(duration); 443 - } 444 - }; 419 + let probed = match symphonia::default::get_probe().format( 420 + &hint, 421 + media_source, 422 + &format_opts, 423 + &meta_opts, 424 + ) { 425 + Ok(probed) => probed, 426 + Err(e) => { 427 + tracing::error!(path = %path.display().to_string().bright_red(), "Error probing file: {}", e); 428 + return Ok(duration); 429 + } 430 + }; 445 431 446 432 if let Some(track) = probed.format.tracks().first() { 447 433 if let Some(duration) = track.codec_params.n_frames {
+2 -2
crates/googledrive/src/cmd/serve.rs
··· 27 27 req: HttpRequest, 28 28 ) -> Result<impl Responder, actix_web::Error> { 29 29 let method = req.match_info().get("method").unwrap_or("unknown"); 30 - println!("Method: {}", method.bright_green()); 30 + tracing::info!(method = %method.bright_green(), "API call"); 31 31 32 32 let conn = data.get_ref().clone(); 33 33 handle(method, &mut payload, &req, conn) ··· 41 41 let addr = format!("{}:{}", host, port); 42 42 43 43 let url = format!("http://{}", addr); 44 - println!("Listening on {}", url.bright_green()); 44 + tracing::info!(url = %url.bright_green(), "Listening on"); 45 45 46 46 let pool = PgPoolOptions::new() 47 47 .max_connections(5)
+6 -1
crates/googledrive/src/repo/google_drive_path.rs
··· 1 + use owo_colors::OwoColorize; 1 2 use sqlx::{Pool, Postgres}; 2 3 3 4 use crate::{ ··· 47 48 .execute(pool) 48 49 .await?; 49 50 50 - println!("{:?}", result); 51 + tracing::info!( 52 + file_id = %file.id.bright_green(), 53 + rows_affected = %result.rows_affected(), 54 + "Google Drive path created" 55 + ); 51 56 52 57 sqlx::query( 53 58 r#"
+27 -79
crates/googledrive/src/scan.rs
··· 104 104 let file = res.json::<File>().await?; 105 105 106 106 if file.mime_type == "application/vnd.google-apps.folder" { 107 - println!("Scanning folder: {}", file.name.bright_green()); 107 + tracing::info!(folder = %file.name.bright_green(), "Scanning folder"); 108 108 109 109 create_google_drive_directory( 110 110 &pool, ··· 172 172 return Ok(()); 173 173 } 174 174 175 - println!("Downloading file: {}", file.name.bright_green()); 175 + tracing::info!(file = %file.name.bright_green(), "Downloading file"); 176 176 177 177 let client = Client::new(); 178 178 ··· 191 191 let mut tmpfile = std::fs::File::create(&tmppath)?; 192 192 tmpfile.write_all(&bytes)?; 193 193 194 - println!( 195 - "Reading file: {}", 196 - &tmppath.clone().display().to_string().bright_green() 197 - ); 194 + tracing::info!(path = %tmppath.display(), "Reading file"); 198 195 199 196 let tagged_file = match Probe::open(&tmppath)?.read() { 200 197 Ok(tagged_file) => tagged_file, 201 198 Err(e) => { 202 - println!("Error opening file: {}", e); 199 + tracing::warn!(file = %file.name.bright_green(), error = %e, "Failed to open file with lofty"); 203 200 return Ok(()); 204 201 } 205 202 }; ··· 208 205 let tag = match primary_tag { 209 206 Some(tag) => tag, 210 207 None => { 211 - println!("No tag found in file"); 208 + tracing::warn!(file = %file.name.bright_green(), "No tag found in file"); 212 209 return Ok(()); 213 210 } 214 211 }; 215 212 216 213 let pictures = tag.pictures(); 217 214 218 - println!( 219 - "Title: {}", 220 - tag.get_string(&lofty::tag::ItemKey::TrackTitle) 221 - .unwrap_or_default() 222 - .bright_green() 223 - ); 224 - println!( 225 - "Artist: {}", 226 - tag.get_string(&lofty::tag::ItemKey::TrackArtist) 227 - .unwrap_or_default() 228 - .bright_green() 229 - ); 230 - println!( 231 - "Album Artist: {}", 232 - tag.get_string(&lofty::tag::ItemKey::AlbumArtist) 233 - .unwrap_or_default() 234 - .bright_green() 235 - ); 236 - println!( 237 - "Album: {}", 238 - tag.get_string(&lofty::tag::ItemKey::AlbumTitle) 239 - .unwrap_or_default() 240 - .bright_green() 241 - ); 242 - println!( 243 - "Lyrics: {}", 244 - tag.get_string(&lofty::tag::ItemKey::Lyrics) 245 - .unwrap_or_default() 246 - .bright_green() 247 - ); 248 - println!("Year: {}", tag.year().unwrap_or_default().bright_green()); 249 - println!( 250 - "Track Number: {}", 251 - tag.track().unwrap_or_default().bright_green() 252 - ); 253 - println!( 254 - "Track Total: {}", 255 - tag.track_total().unwrap_or_default().bright_green() 256 - ); 257 - println!( 258 - "Release Date: {:?}", 259 - tag.get_string(&lofty::tag::ItemKey::OriginalReleaseDate) 260 - .unwrap_or_default() 261 - .bright_green() 262 - ); 263 - println!( 264 - "Recording Date: {:?}", 265 - tag.get_string(&lofty::tag::ItemKey::RecordingDate) 266 - .unwrap_or_default() 267 - .bright_green() 268 - ); 269 - println!( 270 - "Copyright Message: {}", 271 - tag.get_string(&lofty::tag::ItemKey::CopyrightMessage) 272 - .unwrap_or_default() 273 - .bright_green() 274 - ); 275 - println!("Pictures: {:?}", pictures); 215 + tracing::info!(title = %tag.get_string(&lofty::tag::ItemKey::TrackTitle).unwrap_or_default(), "Title"); 216 + tracing::info!(artist = %tag.get_string(&lofty::tag::ItemKey::TrackArtist).unwrap_or_default(), "Artist"); 217 + tracing::info!(album_artist = %tag.get_string(&lofty::tag::ItemKey::AlbumArtist).unwrap_or_default(), "Album artist"); 218 + tracing::info!(album = %tag.get_string(&lofty::tag::ItemKey::AlbumTitle).unwrap_or_default(), "Album"); 219 + tracing::info!(lyrics = %tag.get_string(&lofty::tag::ItemKey::Lyrics).unwrap_or_default(), "Lyrics"); 220 + tracing::info!(year = %tag.year().unwrap_or_default(), "Year"); 221 + tracing::info!(track_number = %tag.track().unwrap_or_default(), "Track number"); 222 + tracing::info!(track_total = %tag.track_total().unwrap_or_default(), "Track total"); 223 + tracing::info!(release_date = %tag.get_string(&lofty::tag::ItemKey::OriginalReleaseDate).unwrap_or_default(), "Release date"); 224 + tracing::info!(recording_date = %tag.get_string(&lofty::tag::ItemKey::RecordingDate).unwrap_or_default(), "Recording date"); 225 + tracing::info!(copyright = %tag.get_string(&lofty::tag::ItemKey::CopyrightMessage).unwrap_or_default(), "Copyright message"); 226 + tracing::info!(pictures = %pictures.len(), "Pictures found"); 276 227 277 228 let title = tag 278 229 .get_string(&lofty::tag::ItemKey::TrackTitle) ··· 304 255 305 256 match track { 306 257 Some(track) => { 307 - println!("Track exists: {}", title.bright_green()); 258 + tracing::info!(title = %title.bright_green(), "Track exists"); 308 259 let parent_drive_id = parent_drive_file_id.as_deref(); 309 - let status = create_google_drive_path( 260 + create_google_drive_path( 310 261 &pool, 311 262 &file, 312 263 &track, ··· 315 266 ) 316 267 .await?; 317 268 318 - println!("status: {:?}", status); 319 269 // TODO: publish file metadata to nats 320 270 } 321 271 None => { 322 - println!("Creating track: {}", title.bright_green()); 272 + tracing::info!(title = %title.bright_green(), "Creating track"); 323 273 324 274 let albumart = 325 275 upload_album_cover(albumart_id.into(), pictures, &access_token).await?; ··· 358 308 })) 359 309 .send() 360 310 .await?; 361 - println!("Track Saved: {} {}", title, response.status()); 311 + tracing::info!(status = %response.status(), "Track saved"); 362 312 tokio::time::sleep(std::time::Duration::from_secs(3)).await; 363 313 364 314 let track = get_track_by_hash(&pool, &hash).await?; 365 315 if let Some(track) = track { 366 316 let parent_drive_id = parent_drive_file_id.as_deref(); 367 - let status = create_google_drive_path( 317 + create_google_drive_path( 368 318 &pool, 369 319 &file, 370 320 &track, 371 321 &google_drive_id, 372 322 parent_drive_id.unwrap_or(""), 373 323 ) 374 - .await; 375 - 376 - println!("status: {:?}", status); 324 + .await?; 377 325 378 326 // TODO: publish file metadata to nats 379 327 ··· 382 330 return Ok(()); 383 331 } 384 332 385 - println!("Failed to create track: {}", title.bright_green()); 333 + tracing::warn!(title = %title.bright_green(), "Failed to create track"); 386 334 } 387 335 } 388 336 ··· 442 390 .send() 443 391 .await?; 444 392 445 - println!("Cover uploaded: {}", response.status()); 393 + tracing::info!(status = %response.status(), "Cover uploaded"); 446 394 447 395 Ok(Some(name)) 448 396 } ··· 466 414 match symphonia::default::get_probe().format(&hint, media_source, &format_opts, &meta_opts) 467 415 { 468 416 Ok(probed) => probed, 469 - Err(_) => { 470 - println!("Error probing file"); 417 + Err(e) => { 418 + tracing::warn!(path = %path.display(), error = %e, "Failed to probe media"); 471 419 return Ok(duration); 472 420 } 473 421 };
+35 -71
crates/jetstream/src/repo.rs
··· 16 16 }, 17 17 webhook_worker::{push_to_queue, AppState}, 18 18 xata::{ 19 - album::Album, album_track::AlbumTrack, artist::Artist, artist_album::ArtistAlbum, 20 - artist_track::ArtistTrack, track::Track, user::User, user_album::UserAlbum, 21 - user_artist::UserArtist, user_track::UserTrack, 19 + album::Album, 20 + album_track::AlbumTrack, 21 + artist::Artist, 22 + artist_album::ArtistAlbum, 23 + artist_track::ArtistTrack, 24 + track::Track, 25 + user::{self, User}, 26 + user_album::UserAlbum, 27 + user_artist::UserArtist, 28 + user_track::UserTrack, 22 29 }, 23 30 }; 24 31 ··· 56 63 57 64 let user_id = save_user(&mut tx, did).await?; 58 65 59 - println!( 60 - "Saving scrobble: {} ", 61 - format!( 62 - "{} - {} - {}", 63 - scrobble_record.title, scrobble_record.artist, scrobble_record.album 64 - ) 65 - .magenta() 66 - ); 66 + tracing::info!(title = %scrobble_record.title.magenta(), artist = %scrobble_record.artist.magenta(), album = %scrobble_record.album.magenta(), "Saving scrobble"); 67 67 68 68 sqlx::query( 69 69 r#" ··· 144 144 { 145 145 Ok(_) => {} 146 146 Err(e) => { 147 - eprintln!("Failed to push to webhook queue: {}", e); 147 + tracing::error!(error = %e, "Failed to push to webhook queue"); 148 148 } 149 149 } 150 150 } ··· 188 188 } 189 189 } 190 190 _ => { 191 - println!("Unsupported operation: {}", commit.operation); 191 + tracing::warn!(operation = %commit.operation, "Unsupported operation"); 192 192 } 193 193 } 194 194 Ok(()) ··· 341 341 .await?; 342 342 343 343 if !albums.is_empty() { 344 - println!("Album already exists: {}", albums[0].title.magenta()); 344 + tracing::info!(name = %albums[0].title.magenta(), "Album already exists"); 345 345 return Ok(albums[0].xata_id.clone()); 346 346 } 347 347 348 - println!("Saving album: {}", scrobble_record.album.magenta()); 348 + tracing::info!(name = %scrobble_record.album, "Saving new album"); 349 349 350 350 let uri: Option<String> = None; 351 351 let artist_uri: Option<String> = None; ··· 402 402 .await?; 403 403 404 404 if !artists.is_empty() { 405 - println!("Artist already exists: {}", artists[0].name.magenta()); 405 + tracing::info!(name = %scrobble_record.album_artist, "Artist already exists"); 406 406 return Ok(artists[0].xata_id.clone()); 407 407 } 408 408 409 - println!("Saving artist: {}", scrobble_record.album_artist.magenta()); 409 + tracing::info!(name = %scrobble_record.album_artist, "Saving new artist"); 410 410 411 411 let uri: Option<String> = None; 412 412 let picture = ""; ··· 450 450 .await?; 451 451 452 452 if !album_tracks.is_empty() { 453 - println!( 454 - "Album track already exists: {}", 455 - format!("{} - {}", album_id, track_id).magenta() 456 - ); 453 + tracing::info!(album_id = %album_id, track_id = %track_id, "Album track already exists"); 457 454 return Ok(()); 458 455 } 459 456 460 - println!( 461 - "Saving album track: {}", 462 - format!("{} - {}", album_id, track_id).magenta() 463 - ); 457 + tracing::info!(album_id = %album_id, track_id = %track_id, "Saving album track"); 464 458 465 459 sqlx::query( 466 460 r#" ··· 492 486 .await?; 493 487 494 488 if !artist_tracks.is_empty() { 495 - println!( 496 - "Artist track already exists: {}", 497 - format!("{} - {}", artist_id, track_id).magenta() 498 - ); 489 + tracing::info!(artist_id = %artist_id, track_id = %track_id, "Artist track already exists"); 499 490 return Ok(()); 500 491 } 501 492 502 - println!( 503 - "Saving artist track: {}", 504 - format!("{} - {}", artist_id, track_id).magenta() 505 - ); 493 + tracing::info!(artist_id = %artist_id, track_id = %track_id, "Saving artist track"); 506 494 507 495 sqlx::query( 508 496 r#" ··· 534 522 .await?; 535 523 536 524 if !artist_albums.is_empty() { 537 - println!( 538 - "Artist album already exists: {}", 539 - format!("{} - {}", artist_id, album_id).magenta() 540 - ); 525 + tracing::info!(artist_id = %artist_id, album_id = %album_id, "Artist album already exists"); 541 526 return Ok(()); 542 527 } 543 528 544 - println!( 545 - "Saving artist album: {}", 546 - format!("{} - {}", artist_id, album_id).magenta() 547 - ); 529 + tracing::info!(artist_id = %artist_id, album_id = %album_id, "Saving artist album"); 548 530 549 531 sqlx::query( 550 532 r#" ··· 585 567 586 568 match artists.is_empty() { 587 569 true => { 588 - println!("Saving artist: {}", record.name.magenta()); 570 + tracing::info!(name = %record.name, "Artist not found in database, inserting new artist"); 589 571 let did = users[0].did.clone(); 590 572 sqlx::query( 591 573 r#" ··· 632 614 .await?; 633 615 634 616 if !user_artists.is_empty() { 635 - println!( 636 - "User artist already exists: {}", 637 - format!("{} - {}", user_id, artist_id).magenta() 638 - ); 617 + tracing::info!(user_id = %user_id, artist_id = %artist_id, "Updating user artist"); 639 618 sqlx::query( 640 619 r#" 641 620 UPDATE user_artists ··· 652 631 return Ok(()); 653 632 } 654 633 655 - println!( 656 - "Saving user artist: {}", 657 - format!("{} - {}", user_id, artist_id).magenta() 658 - ); 634 + tracing::info!(user_id = %user_id, artist_id = %artist_id, "Inserting user artist"); 659 635 660 636 sqlx::query( 661 637 r#" ··· 699 675 700 676 match albums.is_empty() { 701 677 true => { 702 - println!("Saving album: {}", record.title.magenta()); 678 + tracing::info!(title = %record.title, artist = %record.artist, "Album not found in database, inserting new album"); 703 679 let did = users[0].did.clone(); 704 680 sqlx::query( 705 681 r#" ··· 752 728 .await?; 753 729 754 730 if !user_albums.is_empty() { 755 - println!( 756 - "User album already exists: {}", 757 - format!("{} - {}", user_id, album_id).magenta() 758 - ); 731 + tracing::info!(user_id = %user_id, album_id = %album_id, "Updating user album"); 759 732 sqlx::query( 760 733 r#" 761 734 UPDATE user_albums ··· 772 745 return Ok(()); 773 746 } 774 747 775 - println!( 776 - "Saving user album: {}", 777 - format!("{} - {}", user_id, album_id).magenta() 778 - ); 748 + tracing::info!(user_id = %user_id, album_id = %album_id, "Inserting user album"); 779 749 780 750 sqlx::query( 781 751 r#" ··· 822 792 823 793 match tracks.is_empty() { 824 794 true => { 825 - println!("Saving track: {}", record.title.magenta()); 795 + tracing::info!(title = %record.title, artist = %record.artist, album = %record.album, "Track not found in database, inserting new track"); 826 796 let did = users[0].did.clone(); 827 797 sqlx::query( 828 798 r#" ··· 894 864 .await?; 895 865 896 866 if !user_tracks.is_empty() { 897 - println!( 898 - "User track already exists: {}", 899 - format!("{} - {}", user_id, track_id).magenta() 900 - ); 867 + tracing::info!(user_id = %user_id, track_id = %track_id, "Updating user track"); 901 868 sqlx::query( 902 869 r#" 903 870 UPDATE user_tracks ··· 914 881 return Ok(()); 915 882 } 916 883 917 - println!( 918 - "Saving user track: {}", 919 - format!("{} - {}", user_id, track_id).magenta() 920 - ); 884 + tracing::info!(user_id = %user_id, track_id = %track_id, "Inserting user track"); 921 885 922 886 sqlx::query( 923 887 r#" ··· 954 918 .await?; 955 919 956 920 if artists.is_empty() { 957 - println!("Artist not found: {}", record.name.magenta()); 921 + tracing::warn!(name = %record.name, "Artist not found in database"); 958 922 return Ok(()); 959 923 } 960 924 ··· 1023 987 .fetch_all(&mut **tx) 1024 988 .await?; 1025 989 if albums.is_empty() { 1026 - println!("Album not found: {}", record.title.magenta()); 990 + tracing::warn!(title = %record.title, "Album not found in database"); 1027 991 return Ok(()); 1028 992 } 1029 993 let album_id = &albums[0].xata_id; ··· 1082 1046 .await?; 1083 1047 1084 1048 if tracks.is_empty() { 1085 - println!("Track not found: {}", record.title.magenta()); 1049 + tracing::warn!(title = %record.title, "Track not found in database"); 1086 1050 return Ok(()); 1087 1051 } 1088 1052
+6 -9
crates/jetstream/src/subscriber.rs
··· 40 40 let pool = Arc::new(Mutex::new(pool)); 41 41 42 42 let (mut ws_stream, _) = connect_async(&self.service_url).await?; 43 - println!( 44 - "Connected to jetstream at {}", 45 - self.service_url.bright_green() 46 - ); 43 + tracing::info!(url = %self.service_url.bright_green(), "Connected to jetstream at"); 47 44 48 45 while let Some(msg) = ws_stream.next().await { 49 46 match msg { 50 47 Ok(msg) => { 51 48 if let Err(e) = handle_message(state.clone(), pool.clone(), msg).await { 52 - eprintln!("Error handling message: {}", e); 49 + tracing::error!(error = %e, "Error handling message"); 53 50 } 54 51 } 55 52 Err(e) => { 56 - eprintln!("WebSocket error: {}", e); 53 + tracing::error!(error = %e, "WebSocket error"); 57 54 break; 58 55 } 59 56 } ··· 76 73 return Ok::<(), Error>(()); 77 74 } 78 75 79 - println!("Received message: {:#?}", message); 76 + tracing::info!(message = %text.bright_green(), "Received message"); 80 77 if let Some(commit) = message.commit { 81 78 match save_scrobble(state, pool, &message.did, commit).await { 82 79 Ok(_) => { 83 - println!("Scrobble saved successfully"); 80 + tracing::info!(user_id = %message.did.bright_green(), "Scrobble saved successfully"); 84 81 } 85 82 Err(e) => { 86 - eprintln!("Error saving scrobble: {}", e); 83 + tracing::error!(error = %e, "Error saving scrobble"); 87 84 } 88 85 } 89 86 }
+2 -2
crates/jetstream/src/webhook/discord/mod.rs
··· 37 37 embeds: Vec<DiscordEmbed>, 38 38 ) -> reqwest::Result<()> { 39 39 if discord_webhook_url.is_empty() { 40 - println!("DISCORD_WEBHOOK_URL is not set, skipping webhook post"); 40 + tracing::warn!("DISCORD_WEBHOOK_URL is not set, skipping webhook post"); 41 41 return Ok(()); 42 42 } 43 43 ··· 48 48 let res = http.post(discord_webhook_url).json(&body).send().await?; 49 49 if !res.status().is_success() { 50 50 let text = res.text().await.unwrap_or_default(); 51 - eprintln!("Failed to post to Discord webhook: {}", text); 51 + tracing::error!(error = %text, "Failed to post to Discord webhook"); 52 52 } 53 53 Ok(()) 54 54 }
+2 -2
crates/jetstream/src/webhook_worker.rs
··· 79 79 } 80 80 Ok(None) => break, 81 81 Err(e) => { 82 - eprintln!("Failed to pop from Redis: {}", e); 82 + tracing::error!(error = %e, "Failed to pop from Redis"); 83 83 break; 84 84 } 85 85 } ··· 93 93 tokens -= 1; 94 94 95 95 if let Err(e) = discord::post_embeds(&http, &discord_webhook_url, embeds).await { 96 - eprintln!("Failed to post to Discord webhook: {}", e); 96 + tracing::error!(error = %e, "Failed to post to Discord webhook"); 97 97 } 98 98 } 99 99 }
+1 -1
crates/scrobbler/src/auth.rs
··· 37 37 let expected_password = md5::compute(expected_password); 38 38 let expected_password = format!("{:x}", expected_password); 39 39 if expected_password != password_md5 { 40 - println!("{} != {}", expected_password, password_md5); 40 + tracing::error!(expected = %expected_password, provided = %password_md5, "Invalid password"); 41 41 return Err(Error::msg("Invalid password")); 42 42 } 43 43 Ok(())
+1 -1
crates/scrobbler/src/handlers/v1/nowplaying.rs
··· 18 18 let a = form.get("a").unwrap().to_string(); 19 19 let t = form.get("t").unwrap().to_string(); 20 20 21 - println!("Now playing: {} - {} {}", a, t, s.cyan()); 21 + tracing::info!(artist = %a, track = %t, user = %s.cyan(), "Now playing"); 22 22 23 23 let user_id = verify_session_id(cache, &s); 24 24 if let Err(e) = user_id {
+1 -1
crates/scrobbler/src/handlers/v1/submission.rs
··· 29 29 } 30 30 31 31 let user_id = user_id.unwrap(); 32 - println!("Submission: {} - {} {} {} {}", a, t, i, user_id, s.cyan()); 32 + tracing::info!(artist = %a, track = %t, timestamp = %i, user_id = %user_id, "Submission"); 33 33 34 34 match scrobble_v1(pool, cache, &form).await { 35 35 Ok(_) => Ok(HttpResponse::Ok().body("OK\n")),
+1 -4
crates/scrobbler/src/lib.rs
··· 56 56 .parse::<u16>() 57 57 .unwrap_or(7882); 58 58 59 - println!( 60 - "Starting Scrobble server @ {}", 61 - format!("{}:{}", host, port).green() 62 - ); 59 + tracing::info!(url = %format!("http://{}:{}", host, port).bright_green(), "Starting Scrobble server @"); 63 60 64 61 let limiter = web::Data::new( 65 62 Limiter::builder("redis://127.0.0.1")
+2 -8
crates/scrobbler/src/listenbrainz/core/submit.rs
··· 17 17 token: &str, 18 18 ) -> Result<HttpResponse, Error> { 19 19 if payload.listen_type != "playing_now" { 20 - println!("skipping listen type: {}", payload.listen_type.cyan()); 20 + tracing::info!(listen_type = %payload.listen_type.cyan(), "Skipping listen type"); 21 21 return Ok(HttpResponse::Ok().json(json!({ 22 22 "status": "ok", 23 23 "payload": { ··· 62 62 63 63 cache.del(&format!("listenbrainz:cache:{}:{}:{}", artist, track, did))?; 64 64 65 - println!( 66 - "Retryable error on attempt {}/{}: {}", 67 - attempt, 68 - RETRIES, 69 - e.to_string().yellow() 70 - ); 71 - println!("{:#?}", payload); 65 + tracing::error!(error = %e, attempt = attempt, "Retryable error submitting listens for {} - {} (attempt {}/{})", artist, track, attempt, RETRIES); 72 66 73 67 if attempt == RETRIES { 74 68 return Ok(HttpResponse::BadRequest().json(serde_json::json!({
+1 -1
crates/scrobbler/src/listenbrainz/core/validate_token.rs
··· 12 12 }, 13 13 }))), 14 14 Err(e) => { 15 - println!("Error validating token: {}", e); 15 + tracing::error!(error = %e, "Failed to validate token"); 16 16 Ok(HttpResponse::BadRequest().json(serde_json::json!({ 17 17 "error": 4, 18 18 "message": format!("Failed to validate token: {}", e)
+12 -13
crates/scrobbler/src/listenbrainz/handlers.rs
··· 58 58 let body = String::from_utf8_lossy(&payload); 59 59 let req = serde_json::from_str::<SubmitListensRequest>(&body) 60 60 .map_err(|e| { 61 - println!("{}", body); 62 - println!("Error parsing request body: {}", e); 61 + tracing::error!(body = %body, error = %e, "Error parsing request body"); 63 62 e 64 63 }) 65 64 .map_err(actix_web::error::ErrorBadRequest)?; ··· 116 115 })); 117 116 } 118 117 Err(e) => { 119 - println!("Error validating token: {}", e); 118 + tracing::error!(error = %e, "Error validating token"); 120 119 return HttpResponse::InternalServerError().finish(); 121 120 } 122 121 } ··· 127 126 query: web::Query<String>, 128 127 data: web::Data<Arc<Pool<Postgres>>>, 129 128 ) -> impl Responder { 130 - let pool = data.get_ref(); 129 + let _pool = data.get_ref(); 131 130 let query = query.into_inner(); 132 131 133 132 match search_users(&query).await { 134 133 Ok(users) => HttpResponse::Ok().json(users), 135 134 Err(e) => { 136 - println!("Error searching users: {}", e); 135 + tracing::error!(error = %e, "Error searching users"); 137 136 HttpResponse::InternalServerError().finish() 138 137 } 139 138 } ··· 145 144 match get_listens(&user_name).await { 146 145 Ok(listens) => HttpResponse::Ok().json(listens), 147 146 Err(e) => { 148 - println!("Error getting listens for user {}: {}", user_name, e); 147 + tracing::error!(error = %e, "Error getting listens for user {}", user_name); 149 148 HttpResponse::InternalServerError().finish() 150 149 } 151 150 } ··· 157 156 match get_listen_count(&user_name).await { 158 157 Ok(count) => HttpResponse::Ok().json(count), 159 158 Err(e) => { 160 - println!("Error getting listen count for user {}: {}", user_name, e); 159 + tracing::error!(error = %e, "Error getting listen count for user {}", user_name); 161 160 HttpResponse::InternalServerError().finish() 162 161 } 163 162 } ··· 169 168 match get_playing_now(&user_name).await { 170 169 Ok(playing_now) => HttpResponse::Ok().json(playing_now), 171 170 Err(e) => { 172 - println!("Error getting playing now for user {}: {}", user_name, e); 171 + tracing::error!(error = %e, "Error getting playing now for user {}", user_name); 173 172 HttpResponse::InternalServerError().finish() 174 173 } 175 174 } ··· 181 180 match get_top_artists(&user_name).await { 182 181 Ok(artists) => HttpResponse::Ok().json(artists), 183 182 Err(e) => { 184 - println!("Error getting top artists: {}", e); 183 + tracing::error!(error = %e, "Error getting top artists"); 185 184 HttpResponse::InternalServerError().finish() 186 185 } 187 186 } ··· 193 192 match get_top_releases(&user_name).await { 194 193 Ok(releases) => HttpResponse::Ok().json(releases), 195 194 Err(e) => { 196 - println!("Error getting top releases: {}", e); 195 + tracing::error!(error = %e, "Error getting top releases"); 197 196 HttpResponse::InternalServerError().finish() 198 197 } 199 198 } ··· 205 204 match get_top_recordings(&user_name).await { 206 205 Ok(recordings) => HttpResponse::Ok().json(recordings), 207 206 Err(e) => { 208 - println!("Error getting sitewide recordings: {}", e); 207 + tracing::error!(error = %e, "Error getting top recordings"); 209 208 HttpResponse::InternalServerError().finish() 210 209 } 211 210 } ··· 217 216 match get_top_release_groups(&user_name).await { 218 217 Ok(release_groups) => HttpResponse::Ok().json(release_groups), 219 218 Err(e) => { 220 - println!("Error getting top release groups: {}", e); 219 + tracing::error!(error = %e, "Error getting top release groups"); 221 220 HttpResponse::InternalServerError().finish() 222 221 } 223 222 } ··· 229 228 match get_top_recordings(&user_name).await { 230 229 Ok(recordings) => HttpResponse::Ok().json(recordings), 231 230 Err(e) => { 232 - println!("Error getting top recordings: {}", e); 231 + tracing::error!(error = %e, "Error getting top recordings"); 233 232 HttpResponse::InternalServerError().finish() 234 233 } 235 234 }
+3 -3
crates/scrobbler/src/main.rs
··· 58 58 .parse::<u16>() 59 59 .unwrap_or(7882); 60 60 61 - println!( 62 - "Starting Scrobble server @ {}", 63 - format!("{}:{}", host, port).green() 61 + tracing::info!( 62 + url = %format!("http://{}:{}", host, port).bright_green(), 63 + "Starting Scrobble server @" 64 64 ); 65 65 66 66 let limiter = web::Data::new(
+3 -4
crates/scrobbler/src/rocksky.rs
··· 25 25 let token = generate_token(did)?; 26 26 let client = Client::new(); 27 27 28 - println!("Scrobbling track: \n {:#?}", track); 28 + tracing::info!(did = %did, track = ?track, "Scrobbling track"); 29 29 30 30 let response = client 31 31 .post(&format!("{}/now-playing", ROCKSKY_API)) ··· 35 35 .await?; 36 36 37 37 let status = response.status(); 38 - println!("Response status: {}", status); 38 + tracing::info!(did = %did, artist = %track.artist, track = %track.title, status = %status, "Scrobble response"); 39 39 if !status.is_success() { 40 40 let response_text = response.text().await?; 41 - println!("did: {}", did); 42 - println!("Failed to scrobble track: {}", response_text); 41 + tracing::error!(did = %did, response = %response_text, "Failed to scrobble track"); 43 42 return Err(Error::msg(format!( 44 43 "Failed to scrobble track: {}", 45 44 response_text
+21 -51
crates/scrobbler/src/scrobbler.rs
··· 133 133 ); 134 134 let cached = cache.get(&key)?; 135 135 if cached.is_some() { 136 - println!("{}", format!("Cached: {}", key).yellow()); 136 + tracing::info!(key = %key, "Cached:"); 137 137 let track = serde_json::from_str::<Track>(&cached.unwrap())?; 138 138 scrobble.album = Some(track.album.clone()); 139 139 rocksky::scrobble(cache, &did, track, scrobble.timestamp).await?; ··· 144 144 if let Some(mbid) = &scrobble.mbid { 145 145 // let result = repo::track::get_track_by_mbid(pool, mbid).await?; 146 146 let result = mb_client.get_recording(mbid).await?; 147 - println!("{}", "Musicbrainz (mbid)".yellow()); 147 + tracing::info!(%scrobble.artist, %scrobble.track, "Musicbrainz (mbid)"); 148 148 scrobble.album = Some(Track::from(result.clone()).album); 149 149 rocksky::scrobble(cache, &did, result.into(), scrobble.timestamp).await?; 150 150 tokio::time::sleep(std::time::Duration::from_secs(1)).await; ··· 154 154 let result = repo::track::get_track(pool, &scrobble.track, &scrobble.artist).await?; 155 155 156 156 if let Some(track) = result { 157 - println!("{}", "Xata (track)".yellow()); 157 + tracing::info!(artist = %scrobble.artist, track = %scrobble.track, "Xata (track)"); 158 158 scrobble.album = Some(track.album.clone()); 159 159 let album = repo::album::get_album_by_track_id(pool, &track.xata_id).await?; 160 160 let artist = repo::artist::get_artist_by_track_id(pool, &track.xata_id).await?; ··· 204 204 .await?; 205 205 206 206 if let Some(track) = result.tracks.items.first() { 207 - println!("{}", "Spotify (track)".yellow()); 207 + tracing::info!(artist = %scrobble.artist, track = %scrobble.track, "Spotify (track)"); 208 208 scrobble.album = Some(track.album.name.clone()); 209 209 let mut track = track.clone(); 210 210 ··· 232 232 233 233 if let Some(recording) = result.recordings.first() { 234 234 let result = mb_client.get_recording(&recording.id).await?; 235 - println!("{}", "Musicbrainz (recording)".yellow()); 235 + tracing::info!(%scrobble.artist, %scrobble.track, "Musicbrainz (recording)"); 236 236 scrobble.album = Some(Track::from(result.clone()).album); 237 237 rocksky::scrobble(cache, &did, result.into(), scrobble.timestamp).await?; 238 238 tokio::time::sleep(std::time::Duration::from_secs(1)).await; 239 239 continue; 240 240 } 241 241 242 - println!( 243 - "{} {} - {}, skipping", 244 - "Track not found: ".yellow(), 245 - scrobble.artist, 246 - scrobble.track 247 - ); 242 + tracing::info!(artist = %scrobble.artist, track = %scrobble.track, "Track not found, skipping"); 248 243 scrobble.ignored = Some(true); 249 244 } 250 245 ··· 313 308 ); 314 309 let cached = cache.get(&key)?; 315 310 if cached.is_some() { 316 - println!("{}", format!("Cached: {}", key).yellow()); 311 + tracing::info!(key = %key, "Cached:"); 317 312 let track = serde_json::from_str::<Track>(&cached.unwrap())?; 318 313 scrobble.album = Some(track.album.clone()); 319 314 rocksky::scrobble(cache, &did, track, scrobble.timestamp).await?; ··· 324 319 if let Some(mbid) = &scrobble.mbid { 325 320 // let result = repo::track::get_track_by_mbid(pool, mbid).await?; 326 321 let result = mb_client.get_recording(mbid).await?; 327 - println!("{}", "Musicbrainz (mbid)".yellow()); 322 + tracing::info!(%scrobble.artist, %scrobble.track, "Musicbrainz (mbid)"); 328 323 scrobble.album = Some(Track::from(result.clone()).album); 329 324 rocksky::scrobble(cache, &did, result.into(), scrobble.timestamp).await?; 330 325 tokio::time::sleep(std::time::Duration::from_secs(1)).await; ··· 334 329 let result = repo::track::get_track(pool, &scrobble.track, &scrobble.artist).await?; 335 330 336 331 if let Some(track) = result { 337 - println!("{}", "Xata (track)".yellow()); 332 + tracing::info!(artist = %scrobble.artist, track = %scrobble.track, "Xata (track)"); 338 333 scrobble.album = Some(track.album.clone()); 339 334 let album = repo::album::get_album_by_track_id(pool, &track.xata_id).await?; 340 335 let artist = repo::artist::get_artist_by_track_id(pool, &track.xata_id).await?; ··· 384 379 .await?; 385 380 386 381 if let Some(track) = result.tracks.items.first() { 387 - println!("{}", "Spotify (track)".yellow()); 382 + tracing::info!(artist = %scrobble.artist, track = %scrobble.track, "Spotify (track)"); 388 383 scrobble.album = Some(track.album.name.clone()); 389 384 let mut track = track.clone(); 390 385 ··· 412 407 413 408 if let Some(recording) = result.recordings.first() { 414 409 let result = mb_client.get_recording(&recording.id).await?; 415 - println!("{}", "Musicbrainz (recording)".yellow()); 410 + tracing::info!(%scrobble.artist, %scrobble.track, "Musicbrainz (recording)"); 416 411 scrobble.album = Some(Track::from(result.clone()).album); 417 412 rocksky::scrobble(cache, &did, result.into(), scrobble.timestamp).await?; 418 413 tokio::time::sleep(std::time::Duration::from_secs(1)).await; 419 414 return Ok(()); 420 415 } 421 416 422 - println!( 423 - "{} {} - {}, skipping", 424 - "Track not found: ".yellow(), 425 - artist, 426 - track 427 - ); 417 + tracing::info!(artist = %artist, track = %track, "Track not found, skipping"); 428 418 429 419 Ok(()) 430 420 } ··· 435 425 req: &SubmitListensRequest, 436 426 token: &str, 437 427 ) -> Result<(), Error> { 438 - println!("Listenbrainz\n{:#?}", req); 428 + tracing::info!(req = ?req, "Listenbrainz submission"); 439 429 440 430 if req.payload.is_empty() { 441 431 return Err(Error::msg("No payload found")); ··· 481 471 .get(&format!("listenbrainz:cache:{}:{}:{}", artist, track, did))? 482 472 .is_some() 483 473 { 484 - println!( 485 - "{} {} - {}, recently scrobbled", 486 - "Already scrobbled: ".yellow(), 487 - artist, 488 - track 489 - ); 474 + tracing::info!(artist= %artist, track = %track, "Recently scrobbled, skipping"); 490 475 return Ok(()); 491 476 } 492 477 ··· 496 481 .get(&format!("{}:current", spotify_user.email))? 497 482 .is_some() 498 483 { 499 - println!( 500 - "{} {} - {}, currently scrobbling, skipping", 501 - "Currently scrobbling: ".yellow(), 502 - artist, 503 - track 504 - ); 484 + tracing::info!(artist= %artist, track = %track, "Currently scrobbling, skipping"); 505 485 return Ok(()); 506 486 } 507 487 } 508 488 509 489 if cache.get(&format!("nowplaying:{}", did))?.is_some() { 510 - println!( 511 - "{} {} - {}, currently scrobbling, skipping", 512 - "Currently scrobbling: ".yellow(), 513 - artist, 514 - track 515 - ); 490 + tracing::info!(artist= %artist, track = %track, "Currently scrobbling, skipping"); 516 491 return Ok(()); 517 492 } 518 493 ··· 565 540 ); 566 541 let cached = cache.get(&key)?; 567 542 if cached.is_some() { 568 - println!("{}", format!("Cached: {}", key).yellow()); 543 + tracing::info!(key = %key, "Cached"); 569 544 let track = serde_json::from_str::<Track>(&cached.unwrap())?; 570 545 scrobble.album = Some(track.album.clone()); 571 546 rocksky::scrobble(cache, &did, track, scrobble.timestamp).await?; ··· 576 551 if let Some(mbid) = &scrobble.mbid { 577 552 // let result = repo::track::get_track_by_mbid(pool, mbid).await?; 578 553 let result = mb_client.get_recording(mbid).await?; 579 - println!("{}", "Musicbrainz (mbid)".yellow()); 554 + tracing::info!("Musicbrainz (mbid)"); 580 555 scrobble.album = Some(Track::from(result.clone()).album); 581 556 rocksky::scrobble(cache, &did, result.into(), scrobble.timestamp).await?; 582 557 tokio::time::sleep(std::time::Duration::from_secs(1)).await; ··· 586 561 let result = repo::track::get_track(pool, &scrobble.track, &scrobble.artist).await?; 587 562 588 563 if let Some(track) = result { 589 - println!("{}", "Xata (track)".yellow()); 564 + tracing::info!("Xata (track)"); 590 565 scrobble.album = Some(track.album.clone()); 591 566 let album = repo::album::get_album_by_track_id(pool, &track.xata_id).await?; 592 567 let artist = repo::artist::get_artist_by_track_id(pool, &track.xata_id).await?; ··· 636 611 .await?; 637 612 638 613 if let Some(track) = result.tracks.items.first() { 639 - println!("{}", "Spotify (track)".yellow()); 614 + tracing::info!("Spotify (track)"); 640 615 scrobble.album = Some(track.album.name.clone()); 641 616 let mut track = track.clone(); 642 617 ··· 676 651 } 677 652 */ 678 653 679 - println!( 680 - "{} {} - {}, skipping", 681 - "Track not found: ".yellow(), 682 - artist, 683 - track 684 - ); 654 + tracing::warn!(artist = %artist, track = %track, "Track not found, skipping"); 685 655 686 656 Ok(()) 687 657 }
+2 -10
crates/scrobbler/src/spotify/client.rs
··· 36 36 let data = response.text().await?; 37 37 38 38 if data == "Too many requests" { 39 - println!( 40 - "> retry-after {}", 41 - headers.get("retry-after").unwrap().to_str().unwrap() 42 - ); 43 - println!("> {} [get_album]", data); 39 + tracing::info!(retry_after = %headers.get("retry-after").unwrap().to_str().unwrap(), data = %data, "Rate limited on get_album"); 44 40 return Ok(None); 45 41 } 46 42 ··· 56 52 let data = response.text().await?; 57 53 58 54 if data == "Too many requests" { 59 - println!( 60 - "> retry-after {}", 61 - headers.get("retry-after").unwrap().to_str().unwrap() 62 - ); 63 - println!("> {} [get_artist]", data); 55 + tracing::info!(retry_after = %headers.get("retry-after").unwrap().to_str().unwrap(), data = %data, "Rate limited on get_artist"); 64 56 return Ok(None); 65 57 } 66 58
+7 -14
crates/webscrobbler/src/handlers.rs
··· 32 32 req: HttpRequest, 33 33 ) -> Result<impl Responder, actix_web::Error> { 34 34 let id = req.match_info().get("id").unwrap(); 35 - println!("Received scrobble for ID: {}", id.cyan()); 35 + tracing::info!(id = %id.bright_green(), "Received scrobble"); 36 36 37 37 let pool = data.get_ref().clone(); 38 38 ··· 50 50 let body = read_payload!(payload); 51 51 let params = serde_json::from_slice::<ScrobbleRequest>(&body).map_err(|err| { 52 52 let body = String::from_utf8_lossy(&body); 53 - println!("Failed to parse JSON: {}", body); 54 - println!("Failed to parse JSON: {}", err); 53 + tracing::error!(body = %body, error = %err, "Failed to parse JSON"); 55 54 actix_web::error::ErrorBadRequest(format!("Failed to parse JSON: {}", err)) 56 55 })?; 57 56 58 - println!("Parsed scrobble request: {:#?}", params); 57 + tracing::info!(params = ?params, "Parsed scrobble request"); 59 58 60 59 if params.event_name != "scrobble" { 61 - println!("Skipping non-scrobble event: {}", params.event_name.green()); 60 + tracing::info!(event_name = %params.event_name.cyan(), "Skipping non-scrobble event"); 62 61 return Ok(HttpResponse::Ok().body("Skipping non-scrobble event")); 63 62 } 64 63 ··· 75 74 })?; 76 75 77 76 if spotify_token.is_some() { 78 - println!("User has a Spotify token, skipping scrobble"); 77 + tracing::info!("User has a Spotify token, skipping scrobble"); 79 78 return Ok(HttpResponse::Ok().body("User has a Spotify token, skipping scrobble")); 80 79 } 81 80 } ··· 91 90 )); 92 91 93 92 if cached.is_err() { 94 - println!( 95 - "Failed to check cache for Emby scrobble: {}", 96 - cached.unwrap_err() 97 - ); 93 + tracing::error!(artist = %artist, track = %track, error = %cached.unwrap_err(), "Failed to check cache for Emby scrobble"); 98 94 return Ok(HttpResponse::Ok().body("Failed to check cache for Emby scrobble")); 99 95 } 100 96 101 97 if cached.unwrap().is_some() { 102 - println!( 103 - "Skipping duplicate scrobble for Emby: {} - {}", 104 - artist, track 105 - ); 98 + tracing::warn!(artist = %artist, track = %track, "Skipping duplicate scrobble for Emby"); 106 99 return Ok(HttpResponse::Ok().body("Skipping duplicate scrobble for Emby")); 107 100 } 108 101 }
+1 -4
crates/webscrobbler/src/lib.rs
··· 44 44 .parse::<u16>() 45 45 .unwrap_or(7883); 46 46 47 - println!( 48 - "Starting WebScrobbler Webhook @ {}", 49 - format!("{}:{}", host, port).green() 50 - ); 47 + tracing::info!(url = %format!("http://{}:{}", host, port).bright_green(), "Starting WebScrobbler server @"); 51 48 52 49 let limiter = web::Data::new( 53 50 Limiter::builder("redis://127.0.0.1")
+4 -8
crates/webscrobbler/src/rocksky.rs
··· 1 1 use anyhow::Error; 2 - use owo_colors::OwoColorize; 3 2 use reqwest::Client; 4 3 5 4 use crate::{auth::generate_token, cache::Cache, types::Track}; ··· 26 25 let token = generate_token(did)?; 27 26 let client = Client::new(); 28 27 29 - println!("Scrobbling track: \n {:#?}", track); 28 + tracing::info!(did = %did, track = ?track, "Scrobbling track"); 30 29 31 30 let response = client 32 31 .post(&format!("{}/now-playing", ROCKSKY_API)) ··· 36 35 .await?; 37 36 38 37 if !response.status().is_success() { 39 - println!( 40 - "Failed to scrobble track: {}", 41 - response.status().to_string() 42 - ); 38 + tracing::error!(did = %did, artist = %track.artist, track = %track.title, status = %response.status(), "Failed to scrobble track"); 43 39 let text = response.text().await?; 44 - println!("Response: {}", text); 40 + tracing::error!(did = %did, response = %text, "Response"); 45 41 return Err(Error::msg(format!("Failed to scrobble track: {}", text))); 46 42 } 47 43 48 - println!("Scrobbled track: {}", track.title.green()); 44 + tracing::info!(did = %did, artist = %track.artist, track = %track.title, "Scrobbled track"); 49 45 50 46 Ok(()) 51 47 }
+4 -9
crates/webscrobbler/src/scrobbler.rs
··· 34 34 35 35 let cached = cache.get(&key)?; 36 36 if cached.is_some() { 37 - println!("{}", format!("Cached: {}", key).yellow()); 37 + tracing::info!(artist = %scrobble.data.song.parsed.artist, track = %scrobble.data.song.parsed.track, "Using cached track"); 38 38 let track = serde_json::from_str::<Track>(&cached.unwrap())?; 39 39 rocksky::scrobble(cache, &did, track, scrobble.time).await?; 40 40 tokio::time::sleep(std::time::Duration::from_secs(1)).await; ··· 127 127 let result = spotify_client.search(&query).await?; 128 128 129 129 if let Some(track) = result.tracks.items.first() { 130 - println!("{}", "Spotify (track)".yellow()); 130 + tracing::info!("Spotify (track)"); 131 131 let mut track = track.clone(); 132 132 133 133 if let Some(album) = spotify_client.get_album(&track.album.id).await? { ··· 154 154 155 155 if let Some(recording) = result.recordings.first() { 156 156 let result = mb_client.get_recording(&recording.id).await?; 157 - println!("{}", "Musicbrainz (recording)".yellow()); 157 + tracing::info!("Musicbrainz (recording)"); 158 158 rocksky::scrobble(cache, &did, result.into(), scrobble.time).await?; 159 159 tokio::time::sleep(std::time::Duration::from_secs(1)).await; 160 160 return Ok(()); 161 161 } 162 162 163 - println!( 164 - "{} {} - {}, skipping", 165 - "Track not found: ".yellow(), 166 - scrobble.data.song.parsed.artist, 167 - scrobble.data.song.parsed.track 168 - ); 163 + tracing::warn!(artist = %scrobble.data.song.parsed.artist, track = %scrobble.data.song.parsed.track, "Track not found, skipping"); 169 164 170 165 Ok(()) 171 166 }
+2 -10
crates/webscrobbler/src/spotify/client.rs
··· 36 36 let data = response.text().await?; 37 37 38 38 if data == "Too many requests" { 39 - println!( 40 - "> retry-after {}", 41 - headers.get("retry-after").unwrap().to_str().unwrap() 42 - ); 43 - println!("> {} [get_album]", data); 39 + tracing::info!(retry_after = %headers.get("retry-after").unwrap().to_str().unwrap(), data = %data, "Rate limited on get_album"); 44 40 return Ok(None); 45 41 } 46 42 ··· 56 52 let data = response.text().await?; 57 53 58 54 if data == "Too many requests" { 59 - println!( 60 - "> retry-after {}", 61 - headers.get("retry-after").unwrap().to_str().unwrap() 62 - ); 63 - println!("> {} [get_artist]", data); 55 + tracing::info!(retry_after = %headers.get("retry-after").unwrap().to_str().unwrap(), data = %data, "Rate limited on get_artist"); 64 56 return Ok(None); 65 57 } 66 58