diff --git a/Cargo.toml b/Cargo.toml index 14d1ef6..089e0ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,16 +13,16 @@ repository = "https://github.com/trivernis/hydrus-api-rs" [dependencies] serde = {version = "^1.0", features = ["derive"]} reqwest = {version = "0.11.4", features = ["json"]} -log = "0.4.14" +tracing = "0.1.31" mime = "0.3.16" chrono = "0.4.19" regex = "1.5.4" lazy_static = "1.4.0" [dev-dependencies] -env_logger = "0.8.4" maplit = "1.0.2" dotenv = "0.15.0" +tracing-subscriber = "0.3.9" [dev-dependencies.tokio] version = "1.8.0" diff --git a/src/api_core/client.rs b/src/api_core/client.rs index 1315ba4..7905356 100644 --- a/src/api_core/client.rs +++ b/src/api_core/client.rs @@ -32,6 +32,7 @@ use crate::utils::{ use reqwest::Response; use serde::de::DeserializeOwned; use serde::Serialize; +use std::fmt::Debug; static ACCESS_KEY_HEADER: &str = "Hydrus-Client-API-Access-Key"; @@ -56,8 +57,9 @@ impl Client { } /// Starts a get request to the path - async fn get(&self, query: &Q) -> Result { - log::debug!("GET request to {}", E::path()); + #[tracing::instrument(skip(self), level = "trace")] + async fn get(&self, query: &Q) -> Result { + tracing::trace!("GET request to {}", E::path()); let response = self .inner .get(format!("{}/{}", self.base_url, E::path())) @@ -70,7 +72,8 @@ impl Client { } /// Starts a get request to the path associated with the Endpoint Type - async fn get_and_parse( + #[tracing::instrument(skip(self), level = "trace")] + async fn get_and_parse( &self, query: &Q, ) -> Result { @@ -80,8 +83,9 @@ impl Client { } /// Stats a post request to the path associated with the Endpoint Type + #[tracing::instrument(skip(self), level = "trace")] async fn post(&self, body: E::Request) -> Result { - log::debug!("POST request to {}", E::path()); + tracing::trace!("POST request to {}", E::path()); let response = self .inner .post(format!("{}/{}", self.base_url, E::path())) @@ -94,6 +98,7 @@ impl Client { } /// Stats a post request and parses the body as json + #[tracing::instrument(skip(self), level = "trace")] async fn post_and_parse(&self, body: E::Request) -> Result { let response = self.post::(body).await?; @@ -101,8 +106,9 @@ impl Client { } /// Stats a post request to the path associated with the return type + #[tracing::instrument(skip(self, data), level = "trace")] async fn post_binary(&self, data: Vec) -> Result { - log::debug!("Binary POST request to {}", E::path()); + tracing::trace!("Binary POST request to {}", E::path()); let response = self .inner .post(format!("{}/{}", self.base_url, E::path())) @@ -117,10 +123,11 @@ impl Client { } /// Returns an error with the response text content if the status doesn't indicate success + #[tracing::instrument(level = "trace")] async fn extract_error(response: Response) -> Result { if !response.status().is_success() { let msg = response.text().await?; - log::error!("API returned error '{}'", msg); + tracing::error!("API returned error '{}'", msg); Err(Error::Hydrus(msg)) } else { Ok(response) @@ -128,51 +135,55 @@ impl Client { } /// Parses the response as JSOn - async fn extract_content(response: Response) -> Result { - response.json::().await.map_err(Error::from) + #[tracing::instrument(level = "trace")] + async fn extract_content(response: Response) -> Result { + let content = response.json::().await?; + tracing::trace!("response content: {:?}", content); + + Ok(content) } /// Returns the current API version. It's being incremented every time the API changes. + #[tracing::instrument(skip(self), level = "debug")] pub async fn api_version(&self) -> Result { - log::trace!("Getting api version"); self.get_and_parse::(&()).await } /// Creates a new session key + #[tracing::instrument(skip(self), level = "debug")] pub async fn session_key(&self) -> Result { - log::trace!("Getting session key"); self.get_and_parse::(&()).await } /// Verifies if the access key is valid and returns some information about its permissions + #[tracing::instrument(skip(self), level = "debug")] pub async fn verify_access_key(&self) -> Result { - log::trace!("Verifying access key"); self.get_and_parse::(&()).await } /// Returns the list of tag and file services of the client + #[tracing::instrument(skip(self), level = "debug")] pub async fn get_services(&self) -> Result { - log::trace!("Getting services"); self.get_and_parse::(&()).await } /// Adds a file to hydrus - pub async fn add_file(&self, path: S) -> Result { + #[tracing::instrument(skip(self), level = "debug")] + pub async fn add_file(&self, path: S) -> Result { let path = path.to_string(); - log::trace!("Adding file {}", path); self.post_and_parse::(AddFileRequest { path }) .await } /// Adds a file from binary data to hydrus + #[tracing::instrument(skip(self, data), level = "debug")] pub async fn add_binary_file(&self, data: Vec) -> Result { - log::trace!("Adding binary file"); self.post_binary::(data).await } /// Moves files with matching hashes to the trash + #[tracing::instrument(skip(self), level = "debug")] pub async fn delete_files(&self, hashes: Vec) -> Result<()> { - log::trace!("Deleting files {:?}", hashes); self.post::(DeleteFilesRequest { hashes }) .await?; @@ -180,8 +191,8 @@ impl Client { } /// Pulls files out of the trash by hash + #[tracing::instrument(skip(self), level = "debug")] pub async fn undelete_files(&self, hashes: Vec) -> Result<()> { - log::trace!("Undeleting files {:?}", hashes); self.post::(UndeleteFilesRequest { hashes }) .await?; @@ -189,8 +200,8 @@ impl Client { } /// Moves files from the inbox into the archive + #[tracing::instrument(skip(self), level = "debug")] pub async fn archive_files(&self, hashes: Vec) -> Result<()> { - log::trace!("Archiving files {:?}", hashes); self.post::(ArchiveFilesRequest { hashes }) .await?; @@ -198,8 +209,8 @@ impl Client { } /// Moves files from the archive into the inbox + #[tracing::instrument(skip(self), level = "debug")] pub async fn unarchive_files(&self, hashes: Vec) -> Result<()> { - log::trace!("Unarchiving files {:?}", hashes); self.post::(UnarchiveFilesRequest { hashes }) .await?; @@ -207,8 +218,8 @@ impl Client { } /// Returns the list of tags as the client would see them in a human friendly order + #[tracing::instrument(skip(self), level = "debug")] pub async fn clean_tags(&self, tags: Vec) -> Result { - log::trace!("Cleaning tags {:?}", tags); self.get_and_parse::(&[( "tags", string_list_to_json_array(tags), @@ -218,19 +229,18 @@ impl Client { /// Adds tags to files with the given hashes pub async fn add_tags(&self, request: AddTagsRequest) -> Result<()> { - log::trace!("Adding tags {:?}", request); self.post::(request).await?; Ok(()) } /// Searches for files in the inbox, the archive or both + #[tracing::instrument(skip(self), level = "debug")] pub async fn search_files( &self, query: Vec, options: FileSearchOptions, ) -> Result { - log::trace!("Searching for files with tags {:?}", query); let mut args = options.into_query_args(); args.push(("tags", search_query_list_to_json_array(query))); self.get_and_parse::(&args) @@ -238,16 +248,12 @@ impl Client { } /// Returns the metadata for a given list of file_ids or hashes + #[tracing::instrument(skip(self), level = "debug")] pub async fn get_file_metadata( &self, file_ids: Vec, hashes: Vec, ) -> Result { - log::trace!( - "Getting file info for ids {:?} or hashes {:?}", - file_ids, - hashes - ); let query = if file_ids.len() > 0 { ("file_ids", number_list_to_json_array(file_ids)) } else { @@ -258,11 +264,11 @@ impl Client { } /// Returns the metadata for a single file identifier + #[tracing::instrument(skip(self), level = "debug")] pub async fn get_file_metadata_by_identifier( &self, id: FileIdentifier, ) -> Result { - log::trace!("Getting file metadata {:?}", id); let mut response = match id.clone() { FileIdentifier::ID(id) => self.get_file_metadata(vec![id], vec![]).await?, FileIdentifier::Hash(hash) => self.get_file_metadata(vec![], vec![hash]).await?, @@ -275,8 +281,8 @@ impl Client { } /// Returns the bytes of a file from hydrus + #[tracing::instrument(skip(self), level = "debug")] pub async fn get_file(&self, id: FileIdentifier) -> Result { - log::trace!("Getting file {:?}", id); let response = match id { FileIdentifier::ID(id) => { self.get::(&[("file_id", id)]) @@ -300,28 +306,31 @@ impl Client { } /// Returns all files associated with the given url - pub async fn get_url_files>(&self, url: S) -> Result { - log::trace!("Getting files for url {}", url.as_ref()); + #[tracing::instrument(skip(self), level = "debug")] + pub async fn get_url_files + Debug>( + &self, + url: S, + ) -> Result { self.get_and_parse::(&[("url", url.as_ref())]) .await } /// Returns information about the given url - pub async fn get_url_info>(&self, url: S) -> Result { - log::trace!("Getting info for url {}", url.as_ref()); + #[tracing::instrument(skip(self), level = "debug")] + pub async fn get_url_info + Debug>(&self, url: S) -> Result { self.get_and_parse::(&[("url", url.as_ref())]) .await } /// Adds an url to hydrus, optionally with additional tags and a destination page + #[tracing::instrument(skip(self), level = "debug")] pub async fn add_url(&self, request: AddUrlRequest) -> Result { - log::trace!("Adding url {:?}", request); self.post_and_parse::(request).await } /// Associates urls with the given file hashes + #[tracing::instrument(skip(self), level = "debug")] pub async fn associate_urls(&self, urls: Vec, hashes: Vec) -> Result<()> { - log::trace!("Associating urls {:?} with hashes {:?}", urls, hashes); self.post::(AssociateUrlRequest { hashes, urls_to_add: urls, @@ -333,8 +342,8 @@ impl Client { } /// Disassociates urls with the given file hashes + #[tracing::instrument(skip(self), level = "debug")] pub async fn disassociate_urls(&self, urls: Vec, hashes: Vec) -> Result<()> { - log::trace!("Disassociating urls {:?} with hashes {:?}", urls, hashes); self.post::(AssociateUrlRequest { hashes, urls_to_add: vec![], @@ -346,22 +355,25 @@ impl Client { } /// Returns all pages of the client + #[tracing::instrument(skip(self), level = "debug")] pub async fn get_pages(&self) -> Result { - log::trace!("Getting pages"); self.get_and_parse::(&()).await } /// Returns information about a single page - pub async fn get_page_info>(&self, page_key: S) -> Result { - log::trace!("Getting information for page {}", page_key.as_ref()); + #[tracing::instrument(skip(self), level = "debug")] + pub async fn get_page_info + Debug>( + &self, + page_key: S, + ) -> Result { self.get_and_parse::(&[("page_key", page_key.as_ref())]) .await } /// Focuses a page in the client - pub async fn focus_page(&self, page_key: S) -> Result<()> { + #[tracing::instrument(skip(self), level = "debug")] + pub async fn focus_page(&self, page_key: S) -> Result<()> { let page_key = page_key.to_string(); - log::trace!("Focussing page {}", page_key); self.post::(FocusPageRequest { page_key }) .await?; @@ -369,19 +381,14 @@ impl Client { } /// Adds files to a page - pub async fn add_files_to_page( + #[tracing::instrument(skip(self), level = "debug")] + pub async fn add_files_to_page( &self, page_key: S, file_ids: Vec, hashes: Vec, ) -> Result<()> { let page_key = page_key.to_string(); - log::trace!( - "Adding files with ids {:?} or hashes {:?} to page {}", - file_ids, - hashes, - page_key - ); self.post::(AddFilesRequest { page_key, file_ids, @@ -393,8 +400,11 @@ impl Client { } /// Returns all cookies for the given domain - pub async fn get_cookies>(&self, domain: S) -> Result { - log::trace!("Getting cookies"); + #[tracing::instrument(skip(self), level = "debug")] + pub async fn get_cookies + Debug>( + &self, + domain: S, + ) -> Result { self.get_and_parse::(&[("domain", domain.as_ref())]) .await } @@ -402,8 +412,8 @@ impl Client { /// Sets some cookies for some websites. /// Each entry needs to be in the format `[, , , , ]` /// with the types `[String, String, String, String, u64]` + #[tracing::instrument(skip(self), level = "debug")] pub async fn set_cookies(&self, cookies: Vec<[OptionalStringNumber; 5]>) -> Result<()> { - log::trace!("Setting cookies {:?}", cookies); self.post::(SetCookiesRequest { cookies }) .await?; @@ -411,9 +421,9 @@ impl Client { } /// Sets the user agent that is being used for every request hydrus starts - pub async fn set_user_agent(&self, user_agent: S) -> Result<()> { + #[tracing::instrument(skip(self), level = "debug")] + pub async fn set_user_agent(&self, user_agent: S) -> Result<()> { let user_agent = user_agent.to_string(); - log::trace!("Setting user agent to {}", user_agent); self.post::(SetUserAgentRequest { user_agent }) .await?; diff --git a/src/api_core/mod.rs b/src/api_core/mod.rs index 9f87869..6058fcd 100644 --- a/src/api_core/mod.rs +++ b/src/api_core/mod.rs @@ -1,5 +1,6 @@ use serde::de::DeserializeOwned; use serde::Serialize; +use std::fmt::Debug; pub mod access_management; pub mod adding_files; @@ -13,8 +14,8 @@ pub mod searching_and_fetching_files; pub use searching_and_fetching_files::file_sort_type; pub(crate) trait Endpoint { - type Request: Serialize; - type Response: DeserializeOwned; + type Request: Serialize + Debug; + type Response: DeserializeOwned + Debug; fn path() -> String; } diff --git a/src/wrapper/hydrus.rs b/src/wrapper/hydrus.rs index 031ee28..13dbeae 100644 --- a/src/wrapper/hydrus.rs +++ b/src/wrapper/hydrus.rs @@ -10,6 +10,7 @@ use crate::wrapper::service::Services; use crate::wrapper::url::Url; use crate::wrapper::version::Version; use crate::Client; +use std::fmt::Debug; /// A high level wrapper for the hydrus API for easier management of files, tags /// urls etc. @@ -47,13 +48,13 @@ impl Hydrus { } /// Returns the address as an object that can be used to get and set cookies - pub fn address>(&self, address: S) -> Address { + pub fn address + Debug>(&self, address: S) -> Address { Address::from_str(self.client.clone(), address.as_ref()) } /// Returns information about a given url in an object that allows /// further operations with that url - pub async fn url>(&self, url: S) -> Result { + pub async fn url + Debug>(&self, url: S) -> Result { let info = self.client.get_url_info(&url).await?; Ok(Url { @@ -87,7 +88,7 @@ impl Hydrus { } /// Returns a hydrus page by page key - pub async fn page>(&self, page_key: S) -> Result { + pub async fn page + Debug>(&self, page_key: S) -> Result { let info_response = self.client.get_page_info(page_key).await?; Ok(HydrusPage::from_info( @@ -107,7 +108,7 @@ impl Hydrus { } /// Sets the user agent hydrus uses for http requests - pub async fn set_user_agent(&self, user_agent: S) -> Result<()> { + pub async fn set_user_agent(&self, user_agent: S) -> Result<()> { self.client.set_user_agent(user_agent).await } } diff --git a/src/wrapper/or_chain.rs b/src/wrapper/or_chain.rs index 7afacf4..3f0b022 100644 --- a/src/wrapper/or_chain.rs +++ b/src/wrapper/or_chain.rs @@ -47,7 +47,7 @@ where }) .map(Tag::from) .collect(); - log::debug!("String parsed to or-chain {:?}", tags); + tracing::debug!("String parsed to or-chain {:?}", tags); Self { tags } } diff --git a/tests/common.rs b/tests/common.rs index 576bfef..5dda720 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -1,6 +1,5 @@ use hydrus_api::api_core::client::Client; use hydrus_api::Hydrus; -use log::LevelFilter; use std::env; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; @@ -9,9 +8,7 @@ pub fn setup() { lazy_static::lazy_static! { static ref SETUP_DONE: Arc = Arc::new(AtomicBool::new(false)); } if !SETUP_DONE.swap(true, Ordering::SeqCst) { dotenv::dotenv().expect("failed to initialize dotenv"); - env_logger::builder() - .filter_level(LevelFilter::Trace) - .init(); + tracing_subscriber::fmt::init(); } }