Skip to content
This repository has been archived by the owner on Dec 6, 2024. It is now read-only.

Commit

Permalink
Merge pull request #219 from NethermindEth/fix/metrics/options
Browse files Browse the repository at this point in the history
Filter out options for metrics
  • Loading branch information
taco-paco authored Oct 14, 2024
2 parents 7bff28f + 005f36e commit 3db84af
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 50 deletions.
2 changes: 0 additions & 2 deletions api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,10 @@ tracing-subscriber = { version = "^0.3.17", features = [
"smallvec",
] }
tracing-appender = "0.2"
tracing-log = "0.1.3"
uuid = { version = "1.4.1", features = ["serde", "v4"] }
solang-parser = "0.3.2"
crossbeam-queue = "0.3.8"
crossbeam-skiplist = "0.1.1"
fmt = "0.1.0"
yansi = "0.5.1"
thiserror = "1.0.49"
chrono = "0.4.31"
Expand Down
32 changes: 25 additions & 7 deletions api/src/handlers/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::handlers::types::{
ApiCommand, ApiCommandResult, CompilationRequest, CompileResponse, CompiledFile,
};
use crate::handlers::SPAWN_SEMAPHORE;
use crate::metrics::Metrics;
use crate::rate_limiter::RateLimited;
use crate::utils::cleaner::AutoCleanUp;
use crate::utils::hardhat_config::HardhatConfigBuilder;
Expand All @@ -20,21 +21,26 @@ use std::process::Stdio;
use tracing::instrument;
use tracing::{error, info};

pub(crate) const COMPILATION_LABEL_VALUE: &str = "compilation";

#[instrument]
#[post("/compile", format = "json", data = "<request_json>")]
pub async fn compile(
request_json: Json<CompilationRequest>,
_rate_limited: RateLimited,
engine: &State<WorkerEngine>,
) -> Json<CompileResponse> {
info!("/compile/{:?}", request_json.config);

do_compile(request_json.0).await.unwrap_or_else(|e| {
Json(CompileResponse {
file_content: vec![],
message: e.to_string(),
status: "Error".to_string(),
do_compile(request_json.0, &engine.metrics)
.await
.unwrap_or_else(|e| {
Json(CompileResponse {
file_content: vec![],
message: e.to_string(),
status: "Error".to_string(),
})
})
})
}

#[instrument]
Expand Down Expand Up @@ -62,7 +68,10 @@ pub async fn get_compile_result(process_id: String, engine: &State<WorkerEngine>
})
}

pub async fn do_compile(compilation_request: CompilationRequest) -> Result<Json<CompileResponse>> {
pub async fn do_compile(
compilation_request: CompilationRequest,
metrics: &Metrics,
) -> Result<Json<CompileResponse>> {
let zksolc_version = compilation_request.config.version;

// check if the version is supported
Expand Down Expand Up @@ -161,6 +170,11 @@ pub async fn do_compile(compilation_request: CompilationRequest) -> Result<Json<
"Compilation error: {}",
String::from_utf8_lossy(&output.stderr)
);
metrics
.action_failures_total
.with_label_values(&[COMPILATION_LABEL_VALUE])
.inc();

return Ok(Json(CompileResponse {
file_content: vec![],
message: format!(
Expand Down Expand Up @@ -197,6 +211,10 @@ pub async fn do_compile(compilation_request: CompilationRequest) -> Result<Json<
// calling here explicitly to avoid dropping the AutoCleanUp struct
auto_clean_up.clean_up().await;

metrics
.action_successes_total
.with_label_values(&[COMPILATION_LABEL_VALUE])
.inc();
Ok(Json(CompileResponse {
file_content: file_contents,
status: status_code_to_message(status.code()),
Expand Down
79 changes: 62 additions & 17 deletions api/src/handlers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,33 @@ pub mod types;
pub mod utils;
pub mod verify;

use crate::errors::ApiError;
use crate::handlers::compile::do_compile;
use crate::handlers::compiler_version::do_compiler_version;
use crate::handlers::types::{ApiCommand, ApiCommandResult, HealthCheckResponse};
use crate::handlers::verify::do_verify;
use crate::utils::lib::generate_mock_compile_request;
use lazy_static::lazy_static;
use rocket::State;
use tokio::sync::Semaphore;
use tokio::time::Instant;
use tracing::info;
use tracing::instrument;

use crate::errors::ApiError;
use crate::handlers::compile::{do_compile, COMPILATION_LABEL_VALUE};
use crate::handlers::compiler_version::do_compiler_version;
use crate::handlers::types::{ApiCommand, ApiCommandResult, HealthCheckResponse};
use crate::handlers::verify::{do_verify, VERIFICATION_LABEL_VALUE};
use crate::metrics::Metrics;
use crate::utils::lib::generate_mock_compile_request;
use crate::worker::WorkerEngine;

const PROCESS_SPAWN_LIMIT: usize = 8;
lazy_static! {
static ref SPAWN_SEMAPHORE: Semaphore = Semaphore::new(PROCESS_SPAWN_LIMIT);
}

#[instrument]
#[get("/health")]
pub async fn health() -> HealthCheckResponse {
pub async fn health(engine: &State<WorkerEngine>) -> HealthCheckResponse {
info!("/health");

let result = do_compile(generate_mock_compile_request()).await;
let result = do_compile(generate_mock_compile_request(), &engine.metrics).await;

if result.is_ok() {
HealthCheckResponse::ok()
Expand All @@ -42,20 +47,60 @@ pub async fn who_is_this() -> &'static str {
"Who are you?"
}

pub async fn dispatch_command(command: ApiCommand) -> Result<ApiCommandResult, ApiError> {
pub async fn dispatch_command(
command: ApiCommand,
metrics: &Metrics,
) -> Result<ApiCommandResult, ApiError> {
let start_time = Instant::now();

match command {
ApiCommand::CompilerVersion => match do_compiler_version() {
Ok(result) => Ok(ApiCommandResult::CompilerVersion(result)),
Err(e) => Err(e),
},
ApiCommand::Compile(request) => match do_compile(request).await {
Ok(compile_response) => Ok(ApiCommandResult::Compile(compile_response.into_inner())),
Err(e) => Err(e),
},
ApiCommand::Verify(request) => match do_verify(request).await {
Ok(verify_response) => Ok(ApiCommandResult::Verify(verify_response.into_inner())),
Err(e) => Err(e),
},
ApiCommand::Compile(request) => {
let res = match do_compile(request, metrics).await {
Ok(compile_response) => {
Ok(ApiCommandResult::Compile(compile_response.into_inner()))
}
Err(e) => {
metrics
.action_failures_total
.with_label_values(&[COMPILATION_LABEL_VALUE])
.inc();
Err(e)
}
};

let elapsed_time = start_time.elapsed().as_secs_f64();
metrics
.action_duration_seconds
.with_label_values(&[COMPILATION_LABEL_VALUE])
.set(elapsed_time);

res
}
ApiCommand::Verify(request) => {
let res = match do_verify(request, metrics).await {
Ok(verify_response) => Ok(ApiCommandResult::Verify(verify_response.into_inner())),
Err(e) => {
metrics
.action_failures_total
.with_label_values(&[VERIFICATION_LABEL_VALUE])
.inc();

Err(e)
}
};

let elapsed_time = start_time.elapsed().as_secs_f64();
metrics
.action_duration_seconds
.with_label_values(&[VERIFICATION_LABEL_VALUE])
.set(elapsed_time);

res
}
ApiCommand::Shutdown => Ok(ApiCommandResult::Shutdown),
}
}
34 changes: 26 additions & 8 deletions api/src/handlers/verify.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
use rocket::serde::{json, json::Json};
use rocket::{tokio, State};
use std::path::Path;
use std::process::Stdio;
use tracing::info;
use tracing::instrument;

use crate::errors::{ApiError, Result};
use crate::handlers::process::{do_process_command, fetch_process_result};
use crate::handlers::types::{ApiCommand, ApiCommandResult, VerificationRequest, VerifyResponse};
use crate::handlers::SPAWN_SEMAPHORE;
use crate::metrics::Metrics;
use crate::rate_limiter::RateLimited;
use crate::utils::cleaner::AutoCleanUp;
use crate::utils::hardhat_config::HardhatConfigBuilder;
Expand All @@ -10,22 +18,19 @@ use crate::utils::lib::{
ZKSOLC_VERSIONS,
};
use crate::worker::WorkerEngine;
use rocket::serde::{json, json::Json};
use rocket::{tokio, State};
use std::path::Path;
use std::process::Stdio;
use tracing::info;
use tracing::instrument;

pub(crate) const VERIFICATION_LABEL_VALUE: &str = "compilation";

#[instrument]
#[post("/verify", format = "json", data = "<verification_request_json>")]
pub async fn verify(
verification_request_json: Json<VerificationRequest>,
_rate_limited: RateLimited,
engine: &State<WorkerEngine>,
) -> Json<VerifyResponse> {
info!("/verify");

do_verify(verification_request_json.0)
do_verify(verification_request_json.0, &engine.metrics)
.await
.unwrap_or_else(|e| {
Json(VerifyResponse {
Expand Down Expand Up @@ -79,7 +84,10 @@ fn extract_verify_args(request: &VerificationRequest) -> Vec<String> {
args
}

pub async fn do_verify(verification_request: VerificationRequest) -> Result<Json<VerifyResponse>> {
pub async fn do_verify(
verification_request: VerificationRequest,
metrics: &Metrics,
) -> Result<Json<VerifyResponse>> {
let zksolc_version = verification_request.config.zksolc_version.clone();

// check if the version is supported
Expand Down Expand Up @@ -170,12 +178,22 @@ pub async fn do_verify(verification_request: VerificationRequest) -> Result<Json
auto_clean_up.clean_up().await;

if !status.success() {
metrics
.action_failures_total
.with_label_values(&[VERIFICATION_LABEL_VALUE])
.inc();

return Ok(Json(VerifyResponse {
status: "Error".to_string(),
message: String::from_utf8_lossy(&output.stderr).to_string(),
}));
}

metrics
.action_successes_total
.with_label_values(&[VERIFICATION_LABEL_VALUE])
.inc();

Ok(Json(VerifyResponse {
status: "Success".to_string(),
message,
Expand Down
2 changes: 1 addition & 1 deletion api/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ fn create_app(metrics: Metrics) -> Rocket<Build> {
};

// Launch the worker processes
let mut engine = WorkerEngine::new(number_of_workers, queue_size);
let mut engine = WorkerEngine::new(number_of_workers, queue_size, metrics.clone());
engine.start();

// Create a new scheduler
Expand Down
61 changes: 53 additions & 8 deletions api/src/metrics.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
use crate::errors::CoreError;
use prometheus::core::{AtomicU64, GenericCounter, GenericCounterVec};
use prometheus::{Encoder, IntCounter, IntCounterVec, Opts, Registry, TextEncoder};
use prometheus::core::{AtomicF64, AtomicU64, GenericCounter, GenericCounterVec, GenericGaugeVec};
use prometheus::{Encoder, GaugeVec, IntCounter, IntCounterVec, Opts, Registry, TextEncoder};
use rocket::fairing::{Fairing, Info, Kind};
use rocket::http::Method;
use rocket::{Data, Request, State};
use tracing::instrument;

use crate::errors::CoreError;

const NAMESPACE: &str = "zksync_api";

#[derive(Clone)]
pub(crate) struct Metrics {
#[derive(Clone, Debug)]
pub struct Metrics {
pub num_distinct_users: GenericCounterVec<AtomicU64>,
pub num_plugin_launches: GenericCounter<AtomicU64>,
pub num_of_compilations: GenericCounter<AtomicU64>,
pub requests_total: GenericCounter<AtomicU64>,
pub action_failures_total: GenericCounterVec<AtomicU64>,
pub action_successes_total: GenericCounterVec<AtomicU64>,
pub action_duration_seconds: GenericGaugeVec<AtomicF64>,
}

#[rocket::async_trait]
Expand All @@ -24,10 +30,23 @@ impl Fairing for Metrics {
}

async fn on_request(&self, req: &mut Request<'_>, _data: &mut Data<'_>) {
self.requests_total.inc();

match req.method() {
Method::Options => {}
_ => self.update_metrics(req),
}
}
}

impl Metrics {
fn update_metrics(&self, req: &mut Request<'_>) {
if let Some(val) = req.client_ip() {
self.num_distinct_users
.with_label_values(&[val.to_string().as_str()])
.inc();
let ip = val.to_string();
let ip = ip.as_str();
info!("Plugin launched by: {}", ip);

self.num_distinct_users.with_label_values(&[ip]).inc();
}

match req.uri().path().as_str() {
Expand All @@ -37,7 +56,10 @@ impl Fairing for Metrics {
}
}
}

pub(crate) fn create_metrics(registry: Registry) -> Result<Metrics, CoreError> {
const ACTION_LABEL_NAME: &str = "action";

let opts = Opts::new("num_distinct_users", "Number of distinct users").namespace(NAMESPACE);
let num_distinct_users = IntCounterVec::new(opts, &["ip"])?;
registry.register(Box::new(num_distinct_users.clone()))?;
Expand All @@ -50,10 +72,33 @@ pub(crate) fn create_metrics(registry: Registry) -> Result<Metrics, CoreError> {
let num_of_compilations = IntCounter::with_opts(opts)?;
registry.register(Box::new(num_of_compilations.clone()))?;

// Follow naming conventions for new metrics https://prometheus.io/docs/practices/naming/
let opts = Opts::new("requests_total", "Number of requests").namespace(NAMESPACE);
let requests_total = IntCounter::with_opts(opts)?;
registry.register(Box::new(requests_total.clone()))?;

let opts = Opts::new("action_failures_total", "Number of action failures").namespace(NAMESPACE);
let action_failures_total = IntCounterVec::new(opts, &[ACTION_LABEL_NAME])?;
registry.register(Box::new(action_failures_total.clone()))?;

let opts =
Opts::new("action_successes_total", "Number of action successes").namespace(NAMESPACE);
let action_successes_total = IntCounterVec::new(opts, &[ACTION_LABEL_NAME])?;
registry.register(Box::new(action_successes_total.clone()))?;

let opts =
Opts::new("action_duration_seconds", "Duration of action in seconds").namespace(NAMESPACE);
let action_duration_seconds = GaugeVec::new(opts, &[ACTION_LABEL_NAME])?;
registry.register(Box::new(action_duration_seconds.clone()))?;

Ok(Metrics {
num_distinct_users,
num_plugin_launches,
num_of_compilations,
requests_total,
action_failures_total,
action_successes_total,
action_duration_seconds,
})
}

Expand Down
Loading

0 comments on commit 3db84af

Please sign in to comment.