summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <git@iximeow.net>2022-12-29 19:08:01 +0000
committeriximeow <git@iximeow.net>2022-12-29 19:08:01 +0000
commit0832c96c116f4c3a28bd22a0cdd287a3b0764c7b (patch)
tree9b58beaf733a7ded11eb8519d37d41653f1e77fe
parente28b277980763b88d2828812bff2c0b9546d3d25 (diff)
record and present metrics
-rw-r--r--src/ci_driver.rs11
-rw-r--r--src/ci_runner.rs3
-rw-r--r--src/dbctx.rs35
-rw-r--r--src/main.rs21
-rw-r--r--src/sql.rs11
5 files changed, 80 insertions, 1 deletions
diff --git a/src/ci_driver.rs b/src/ci_driver.rs
index 47892d6..d0e56cb 100644
--- a/src/ci_driver.rs
+++ b/src/ci_driver.rs
@@ -243,6 +243,17 @@ impl ClientJob {
"object_id": "10",
})).await.unwrap();
},
+ "metric" => {
+ let name = msg.as_object().unwrap().get("name").unwrap().as_str().unwrap();
+ let value = msg.as_object().unwrap().get("value").unwrap().as_str().unwrap();
+
+ self.dbctx.insert_metric(self.job.id, name, value)
+ .expect("TODO handle metric insert error?");
+ }
+ "command" => {
+ // record information about commands, start/stop, etc. probably also allow
+ // artifacts to be attached to commands and default to attaching stdout/stderr?
+ }
other => {
eprintln!("unhandled message kind {:?} ({:?})", msg_kind, msg);
}
diff --git a/src/ci_runner.rs b/src/ci_runner.rs
index a47d298..97d8505 100644
--- a/src/ci_runner.rs
+++ b/src/ci_runner.rs
@@ -82,7 +82,8 @@ impl RunningJob {
async fn send_metric(&mut self, name: &str, value: String) -> Result<(), String> {
self.client.send(serde_json::json!({
"kind": "metric",
- "value": value.to_string(),
+ "name": name,
+ "value": value,
})).await
.map_err(|e| format!("failed to send metric {}: {:?})", name, e))
}
diff --git a/src/dbctx.rs b/src/dbctx.rs
index 804f083..67740e8 100644
--- a/src/dbctx.rs
+++ b/src/dbctx.rs
@@ -39,6 +39,14 @@ pub enum TokenValidity {
}
#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct MetricRecord {
+ pub id: u64,
+ pub job_id: u64,
+ pub name: String,
+ pub value: String
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ArtifactRecord {
pub id: u64,
pub job_id: u64,
@@ -58,6 +66,7 @@ impl DbCtx {
let conn = self.conn.lock().unwrap();
conn.execute(sql::CREATE_ARTIFACTS_TABLE, ()).unwrap();
conn.execute(sql::CREATE_JOBS_TABLE, ()).unwrap();
+ conn.execute(sql::CREATE_METRICS_TABLE, ()).unwrap();
conn.execute(sql::CREATE_COMMITS_TABLE, ()).unwrap();
conn.execute(sql::CREATE_REPOS_TABLE, ()).unwrap();
conn.execute(sql::CREATE_REPO_NAME_INDEX, ()).unwrap();
@@ -67,6 +76,17 @@ impl DbCtx {
Ok(())
}
+ pub fn insert_metric(&self, job_id: u64, name: &str, value: &str) -> Result<(), String> {
+ let conn = self.conn.lock().unwrap();
+ conn
+ .execute(
+ "insert into metrics (job_id, name, value) values (?1, ?2, ?3) on conflict (job_id, name) do update set value=excluded.value",
+ (job_id, name, value)
+ )
+ .expect("can upsert");
+ Ok(())
+ }
+
pub fn new_commit(&self, sha: &str) -> Result<u64, String> {
let conn = self.conn.lock().unwrap();
conn
@@ -218,6 +238,21 @@ impl DbCtx {
Ok(conn.last_insert_rowid() as u64)
}
+ pub fn metrics_for_job(&self, job: u64) -> Result<Vec<MetricRecord>, String> {
+ let conn = self.conn.lock().unwrap();
+
+ let mut metrics_query = conn.prepare(sql::METRICS_FOR_JOB).unwrap();
+ let mut result = metrics_query.query([job]).unwrap();
+ let mut metrics = Vec::new();
+
+ while let Some(row) = result.next().unwrap() {
+ let (id, job_id, name, value): (u64, u64, String, String) = row.try_into().unwrap();
+ metrics.push(MetricRecord { id, job_id, name, value });
+ }
+
+ Ok(metrics)
+ }
+
pub fn artifacts_for_job(&self, job: u64) -> Result<Vec<ArtifactRecord>, String> {
let conn = self.conn.lock().unwrap();
diff --git a/src/main.rs b/src/main.rs
index a96c5e4..f14b325 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -23,6 +23,7 @@ use std::time::{SystemTime, UNIX_EPOCH};
use hmac::{Hmac, Mac};
use sha2::Sha256;
+mod io;
mod sql;
mod notifier;
mod dbctx;
@@ -245,6 +246,23 @@ async fn handle_commit_status(Path(path): Path<(String, String, String)>, State(
None
};
+ let metrics = ctx.metrics_for_job(job_id).unwrap();
+ let metrics_section = if metrics.len() > 0 {
+ let mut section = String::new();
+ section.push_str("<div>");
+ section.push_str("<h3>metrics</h3>");
+ section.push_str("<table style='font-family: monospace;'>");
+ section.push_str("<tr><th>name</th><th>value</th></tr>");
+ for metric in metrics {
+ section.push_str(&format!("<tr><td>{}</td><td>{}</td></tr>", &metric.name, &metric.value));
+ }
+ section.push_str("</table>");
+ section.push_str("</div>");
+ Some(section)
+ } else {
+ None
+ };
+
let mut html = String::new();
html.push_str("<html>\n");
html.push_str(&format!(" {}\n", head));
@@ -262,6 +280,9 @@ async fn handle_commit_status(Path(path): Path<(String, String, String)>, State(
html.push_str(" <div>last build output</div>\n");
html.push_str(&format!(" {}\n", output));
}
+ if let Some(metrics) = metrics_section {
+ html.push_str(&metrics);
+ }
html.push_str(" </body>\n");
html.push_str("</html>");
diff --git a/src/sql.rs b/src/sql.rs
index 21572da..7bd33fd 100644
--- a/src/sql.rs
+++ b/src/sql.rs
@@ -50,6 +50,14 @@ pub const CREATE_JOBS_TABLE: &'static str = "\
build_result INTEGER,
final_status TEXT);";
+pub const CREATE_METRICS_TABLE: &'static str = "\
+ CREATE TABLE IF NOT EXISTS metrics (id INTEGER PRIMARY KEY AUTOINCREMENT,
+ job_id INTEGER,
+ name TEXT,
+ value TEXT,
+ UNIQUE(job_id, name)
+ );";
+
pub const CREATE_COMMITS_TABLE: &'static str = "\
CREATE TABLE IF NOT EXISTS commits (id INTEGER PRIMARY KEY AUTOINCREMENT, sha TEXT UNIQUE);";
@@ -90,6 +98,9 @@ pub const PENDING_JOBS: &'static str = "\
pub const LAST_ARTIFACTS_FOR_JOB: &'static str = "\
select * from artifacts where job_id=?1 and (name like \"%(stderr)%\" or name like \"%(stdout)%\") order by id desc limit 2;";
+pub const METRICS_FOR_JOB: &'static str = "\
+ select * from metrics where job_id=?1 order by id asc;";
+
pub const COMMIT_TO_ID: &'static str = "\
select id from commits where sha=?1;";