Initial stabilization #1

Merged
dzu merged 10 commits from stabilize-v1 into main 2026-02-20 16:23:43 +01:00
3 changed files with 130 additions and 28 deletions
Showing only changes of commit 479d6fe414 - Show all commits

ench: use tracing for logging

Artem Diachenko 2026-02-20 13:43:31 +00:00

67
Cargo.lock generated
View file

@ -11,6 +11,8 @@ dependencies = [
"secrecy",
"serde_json",
"thiserror",
"tracing",
"tracing-subscriber",
]
[[package]]
@ -354,6 +356,12 @@ version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
[[package]]
name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.182"
@ -406,6 +414,15 @@ version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "nu-ansi-term"
version = "0.50.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "once_cell"
version = "1.21.3"
@ -587,6 +604,15 @@ dependencies = [
"zmij",
]
[[package]]
name = "sharded-slab"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
dependencies = [
"lazy_static",
]
[[package]]
name = "shlex"
version = "1.3.0"
@ -674,6 +700,15 @@ dependencies = [
"syn",
]
[[package]]
name = "thread_local"
version = "1.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
dependencies = [
"cfg-if",
]
[[package]]
name = "tinystr"
version = "0.8.2"
@ -714,6 +749,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
dependencies = [
"once_cell",
"valuable",
]
[[package]]
@ -726,6 +762,31 @@ dependencies = [
"tracing",
]
[[package]]
name = "tracing-log"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
dependencies = [
"log",
"once_cell",
"tracing-core",
]
[[package]]
name = "tracing-subscriber"
version = "0.3.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e"
dependencies = [
"nu-ansi-term",
"sharded-slab",
"smallvec",
"thread_local",
"tracing-core",
"tracing-log",
]
[[package]]
name = "unicode-ident"
version = "1.0.24"
@ -750,6 +811,12 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]]
name = "valuable"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
[[package]]
name = "vcpkg"
version = "0.2.15"

View file

@ -9,3 +9,5 @@ isahc = { version = "1.7.2", features = ["static-ssl", "static-curl"] }
serde_json = "1.0.149"
secrecy = "0.10.3"
thiserror = "2.0.18"
tracing-subscriber = { version = "0.3.22" }
tracing = { version = "0.1.44", features = ["attributes"] }

View file

@ -1,6 +1,7 @@
use std::{ffi::OsString, io::Read, path::PathBuf, str::FromStr, string::FromUtf8Error};
use anyhow::{Context, Result, bail};
use anyhow::bail;
use anyhow::{Context, Result};
use isahc::{
HttpClient, HttpClientBuilder, Request,
auth::{Authentication, Credentials},
@ -8,7 +9,20 @@ use isahc::{
http::{Method, StatusCode, header},
};
use secrecy::SecretString;
use tracing::{Level, debug, error};
use tracing_subscriber::fmt::format::FmtSpan;
pub fn setup_logger(debug: bool) {
tracing_subscriber::fmt()
.with_ansi(true)
.with_level(true)
.with_max_level(if debug { Level::DEBUG } else { Level::INFO })
.with_span_events(FmtSpan::CLOSE)
.init();
debug!("Logger set up");
}
#[tracing::instrument(level = "debug")]
pub fn paths_parser(input: OsString) -> Result<Vec<PathBuf>, FromUtf8Error> {
let input = String::from_utf8(input.into_encoded_bytes())?;
let mut paths = Vec::new();
@ -17,6 +31,7 @@ pub fn paths_parser(input: OsString) -> Result<Vec<PathBuf>, FromUtf8Error> {
Ok(ok) => ok,
});
}
debug!(?paths, "Parsed paths");
Ok(paths)
}
@ -33,6 +48,7 @@ pub enum CacheKeyError {
Comma { offset: usize },
}
#[tracing::instrument(level = "debug", fields(return))]
pub fn key_parser(input: OsString) -> Result<CacheKey, CacheKeyError> {
let input = String::from_utf8(input.into_encoded_bytes())?;
let mut len = 0;
@ -56,6 +72,7 @@ pub enum ActionsTokenError {
NotUtf8,
}
#[tracing::instrument(level = "debug")]
pub fn actions_token() -> Result<SecretString, ActionsTokenError> {
let os_str = std::env::var_os("ACTIONS_RUNTIME_TOKEN").ok_or(ActionsTokenError::NotPresent)?;
let str =
@ -63,6 +80,7 @@ pub fn actions_token() -> Result<SecretString, ActionsTokenError> {
Ok(SecretString::new(str.into_boxed_str()))
}
#[derive(Debug)]
pub struct Client {
http_client: HttpClient,
base_url: String,
@ -72,18 +90,22 @@ pub struct Client {
pub struct CacheId(u64);
impl Client {
#[tracing::instrument(level = "debug", fields(base_url = tracing::field::Empty), skip_all)]
pub fn new(actions_token: impl AsRef<str>, base_url: impl Into<String>) -> Result<Self> {
let http_client = HttpClientBuilder::new()
.authentication(Authentication::basic())
.credentials(Credentials::new("Bearer", actions_token.as_ref()))
.build()
.context("initializing the client")?;
let base_url = base_url.into();
tracing::span::Span::current().record("base_url", &base_url);
Ok(Self {
http_client,
base_url: base_url.into(),
base_url,
})
}
#[tracing::instrument(level = "info", skip(cache))]
pub fn save_cache(&self, key: &CacheKey, cache: Vec<u8>) -> Result<()> {
let cache_len = cache.len();
let cache_id = self.reserve(key, cache_len).context("reserving cache")?;
@ -96,8 +118,10 @@ impl Client {
Ok(())
}
#[tracing::instrument(level = "debug", fields(return))]
fn reserve(&self, key: &CacheKey, cache_size: usize) -> Result<CacheId> {
let uri = format!("{}_apis/artifactcache/caches", self.base_url);
debug!(uri);
let request = Request::builder()
.uri(uri)
.method(Method::POST)
@ -114,6 +138,7 @@ impl Client {
.http_client
.send(request)
.context("sending the request")?;
debug!(?response);
let status = response.status();
let mut body = Vec::with_capacity(100);
response
@ -121,16 +146,13 @@ impl Client {
.read_to_end(&mut body)
.context("reading response body")?;
if status != StatusCode::OK {
bail!(
"Failed reserving a cache (status {status}): {:?}",
String::from_utf8_lossy(&body)
);
error!(?status, "failed sending a request");
bail!("failed sending a request");
}
let body_value =
serde_json::from_slice::<serde_json::Value>(&body).context("parsing response body")?;
println!("{body_value:#?}");
debug!(body = ?body_value);
let cache_id = body_value
.get("cacheId")
@ -141,8 +163,10 @@ impl Client {
Ok(CacheId(cache_id))
}
#[tracing::instrument(level = "debug", skip(archive))]
fn save(&self, id: CacheId, archive: Vec<u8>) -> Result<()> {
let uri = format!("{}_apis/artifactcache/caches/{}", self.base_url, id.0);
debug!(uri);
let request = Request::builder()
.uri(uri)
.method(Method::PATCH)
@ -153,28 +177,33 @@ impl Client {
)
.body(archive)
.context("building the request")?;
let mut response = self
.http_client
.send(request)
.context("sending the request")?;
debug!(?response);
let status = response.status();
let mut body = Vec::with_capacity(100);
response
.body_mut()
.read_to_end(&mut body)
.context("reading response body")?;
if status != StatusCode::OK {
bail!(
"Failed saving a cache (status {status}): {:?}",
String::from_utf8_lossy(&body)
);
error!(?status, body = ?String::from_utf8_lossy(&body), "failed sending a request");
bail!("failed sending a request");
}
Ok(())
}
#[tracing::instrument(level = "debug")]
fn commit_cache(&self, id: CacheId, cache_size: usize) -> Result<()> {
let uri = format!("{}_apis/artifactcache/caches/{}", self.base_url, id.0);
debug!(uri);
let request = Request::builder()
.uri(uri)
.method(Method::POST)
@ -189,6 +218,8 @@ impl Client {
.http_client
.send(request)
.context("sending the request")?;
debug!(?response);
let status = response.status();
if status != StatusCode::OK {
let mut body = Vec::with_capacity(100);
@ -196,15 +227,14 @@ impl Client {
.body_mut()
.read_to_end(&mut body)
.context("reading response body")?;
bail!(
"Failed reserving a cache (status {status}): {:?}",
String::from_utf8_lossy(&body)
);
error!(?status, body = ?String::from_utf8_lossy(&body), "failed sending a request");
bail!("failed sending a request");
}
Ok(())
}
#[tracing::instrument(level = "info")]
pub fn load_cache(&self, key: &CacheKey) -> Result<Option<Box<[u8]>>> {
let Some(cache_location) = self.get_cache_entry(key).context("getting cache entry")? else {
// cache miss
@ -218,12 +248,14 @@ impl Client {
Ok(Some(cache))
}
#[tracing::instrument(level = "debug", fields(return))]
fn get_cache_entry(&self, key: &CacheKey) -> Result<Option<String>> {
let uri = format!(
"{}_apis/artifactcache/cache?keys={}&version=0",
self.base_url, key.0
);
println!("cache entry uri: {uri}");
debug!(uri);
let request = Request::builder()
.uri(uri)
.method(Method::GET)
@ -233,6 +265,8 @@ impl Client {
.http_client
.send(request)
.context("sending the request")?;
debug!(?response);
let status = response.status();
if status == StatusCode::NO_CONTENT {
// cache miss
@ -244,16 +278,15 @@ impl Client {
.read_to_end(&mut body)
.context("reading response body")?;
if status != StatusCode::OK {
bail!(
"Failed reading a cache entry (status {status}): {:?}",
str::from_utf8(&body)
);
error!(?status, body = ?String::from_utf8_lossy(&body), "failed sending a request");
bail!("failed sending a request");
}
let body_val =
let body_value =
serde_json::from_slice::<serde_json::Value>(&body).context("parsing response body")?;
debug!(body = ?body_value);
let location = body_val
let location = body_value
.get("archiveLocation")
.context("not cache location field")?
.as_str()
@ -262,8 +295,8 @@ impl Client {
Ok(Some(location.to_string()))
}
#[tracing::instrument(level = "debug")]
fn download_cache(&self, location: String) -> Result<Box<[u8]>> {
println!("cache data uri: {location}");
let request = Request::builder()
.uri(location)
.method(Method::GET)
@ -273,6 +306,8 @@ impl Client {
.http_client
.send(request)
.context("sending the request")?;
debug!(?response);
let status = response.status();
let mut body = Vec::with_capacity(100);
response
@ -280,10 +315,8 @@ impl Client {
.read_to_end(&mut body)
.context("reading response body")?;
if status != StatusCode::OK {
bail!(
"Failed downloading the cache (status {status}): {:?}",
str::from_utf8(&body)
);
error!(?status, body = ?String::from_utf8_lossy(&body), "failed sending a request");
bail!("failed sending a request");
}
Ok(body.into_boxed_slice())