feat: impl api /logs

This commit is contained in:
imlonghao 2022-01-23 14:38:21 +08:00
parent bff1851e43
commit 8fd2822ba3
5 changed files with 389 additions and 2 deletions

View file

@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
- Implemente API for `/logs`
## [0.1.0] - 2022-01-23
### Added

227
Cargo.lock generated
View file

@ -232,18 +232,48 @@ dependencies = [
"thiserror",
]
[[package]]
name = "anyhow"
version = "1.0.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94a45b455c14666b85fc40a019e8ab9eb75e3a124e05494f5397122bc9eb06e0"
[[package]]
name = "archlinuxcn-packages"
version = "0.1.0"
dependencies = [
"actix-web",
"ansi-to-html",
"anyhow",
"bigdecimal",
"cached",
"chrono",
"deadpool-postgres",
"enum-display-derive",
"pg_bigdecimal",
"postgres-types",
"serde",
"tokio-postgres",
"yaml-rust",
]
[[package]]
name = "async-mutex"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e"
dependencies = [
"event-listener",
]
[[package]]
name = "async-rwlock"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "261803dcc39ba9e72760ba6e16d0199b1eef9fc44e81bffabbebb9f5aea3906c"
dependencies = [
"async-mutex",
"event-listener",
]
[[package]]
@ -269,6 +299,17 @@ version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
[[package]]
name = "bigdecimal"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6aaf33151a6429fe9211d1b276eafdf70cdff28b071e76c0b0e1503221ea3744"
dependencies = [
"num-bigint",
"num-integer",
"num-traits",
]
[[package]]
name = "bitflags"
version = "1.3.2"
@ -326,6 +367,40 @@ dependencies = [
"bytes",
]
[[package]]
name = "cached"
version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af4dfac631a8e77b2f327f7852bb6172771f5279c4512efe79fad6067b37be3d"
dependencies = [
"async-mutex",
"async-rwlock",
"async-trait",
"cached_proc_macro",
"cached_proc_macro_types",
"futures",
"hashbrown",
"once_cell",
]
[[package]]
name = "cached_proc_macro"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "725f434d6da2814b989bd905c62ca28a9383feff7440210dc279665fbbbc9511"
dependencies = [
"cached_proc_macro_types",
"darling",
"quote",
"syn",
]
[[package]]
name = "cached_proc_macro_types"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a4f925191b4367301851c6d99b09890311d74b0d43f274c0b34c86d308a3663"
[[package]]
name = "cc"
version = "1.0.72"
@ -398,6 +473,41 @@ dependencies = [
"generic-array",
]
[[package]]
name = "darling"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0d720b8683f8dd83c65155f0530560cba68cd2bf395f6513a483caee57ff7f4"
dependencies = [
"darling_core",
"darling_macro",
]
[[package]]
name = "darling_core"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a340f241d2ceed1deb47ae36c4144b2707ec7dd0b649f894cb39bb595986324"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn",
]
[[package]]
name = "darling_macro"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72c41b3b7352feb3211a0d743dc5700a4e3b60f51bd2b368892d1e0f9a95f44b"
dependencies = [
"darling_core",
"quote",
"syn",
]
[[package]]
name = "deadpool"
version = "0.9.2"
@ -476,6 +586,12 @@ dependencies = [
"syn",
]
[[package]]
name = "event-listener"
version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71"
[[package]]
name = "fallible-iterator"
version = "0.2.0"
@ -692,6 +808,12 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "idna"
version = "0.2.3"
@ -755,6 +877,12 @@ version = "0.2.113"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eef78b64d87775463c549fbd80e19249ef436ea3bf1de2a1eb7e717ec7fab1e9"
[[package]]
name = "linked-hash-map"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
[[package]]
name = "local-channel"
version = "0.1.2"
@ -872,6 +1000,40 @@ dependencies = [
"winapi",
]
[[package]]
name = "num"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606"
dependencies = [
"num-bigint",
"num-complex",
"num-integer",
"num-iter",
"num-rational",
"num-traits",
]
[[package]]
name = "num-bigint"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-complex"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26873667bbbb7c5182d4a37c1add32cdf09f841af72da53318fdb81543c15085"
dependencies = [
"num-traits",
]
[[package]]
name = "num-integer"
version = "0.1.44"
@ -882,6 +1044,29 @@ dependencies = [
"num-traits",
]
[[package]]
name = "num-iter"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a"
dependencies = [
"autocfg",
"num-bigint",
"num-integer",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.14"
@ -953,6 +1138,19 @@ version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "pg_bigdecimal"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aaef67cc0b89c04b673c77c16ff90d27f01d83fc74531b6fd881b81bddf188df"
dependencies = [
"bigdecimal",
"byteorder",
"bytes",
"num",
"postgres",
]
[[package]]
name = "phf"
version = "0.10.1"
@ -983,6 +1181,20 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "postgres"
version = "0.19.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb76d6535496f633fa799bb872ffb4790e9cbdedda9d35564ca0252f930c0dd5"
dependencies = [
"bytes",
"fallible-iterator",
"futures",
"log",
"tokio",
"tokio-postgres",
]
[[package]]
name = "postgres-derive"
version = "0.4.1"
@ -1254,6 +1466,12 @@ dependencies = [
"unicode-normalization",
]
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "subtle"
version = "2.4.1"
@ -1481,6 +1699,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "yaml-rust"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
dependencies = [
"linked-hash-map",
]
[[package]]
name = "zstd"
version = "0.9.2+zstd.1.5.1"

View file

@ -8,9 +8,14 @@ edition = "2021"
[dependencies]
actix-web = "4.0.0-beta.21"
ansi-to-html = "0.1.0"
anyhow = "1.0.53"
bigdecimal = "0.3.0"
cached = "0.30.0"
chrono = "0.4.19"
deadpool-postgres = "0.10.1"
enum-display-derive = "0.1.1"
pg_bigdecimal = "0.1.4"
postgres-types = { version = "0.2.2", features = ["derive"]}
serde = { version = "1.0.135", features = ["derive"] }
tokio-postgres = { version = "0.7.5", features = ["with-chrono-0_4"]}
yaml-rust = "0.4.5"

87
html/logs.html Normal file
View file

@ -0,0 +1,87 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Archlinuxcn Packages</title>
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.20/css/jquery.dataTables.min.css"
integrity="sha256-YY1izqyhIj4W3iyJOaGWOpXDSwrHWFL4Nfk+W0LyCHE=" crossorigin="anonymous">
</head>
<body>
<table id="l" class="stripe cell-border" style="text-align:center">
</table>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.min.js"
integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/datatables.net@1.10.20/js/jquery.dataTables.min.js"
integrity="sha256-LXQzPhL1IRyKkA7HpCOBi8I+OC8HqzHUYkjK8S+LKTs=" crossorigin="anonymous"></script>
<script>
$(document).ready(function () {
$('#l').DataTable({
"searchDelay": 100,
"iDisplayLength": 100,
"aLengthMenu": [[100, 250, 500, 1000, -1], [100, 250, 500, 1000, "所有"]],
"ajax": {
url: "/imlonghao-api/logs",
dataSrc: ""
},
"order": [[5, "desc"]],
"columnDefs": [
{
targets: 0,
title: "包名",
data: "pkgbase"
},
{
targets: 1,
title: "打包者",
data: "maintainer"
},
{
targets: 2,
title: "版本号",
data: "pkg_version"
},
{
targets: 3,
title: "状态",
data: "result"
},
{
targets: 4,
title: "持续时间(秒)",
data: "elapsed"
},
{
targets: 5,
title: "CPU 使用率(%",
data: "cpu"
},
{
targets: 6,
title: "内存使用率GiB",
data: "memory"
},
{
targets: 7,
title: "打包时间",
data: "ts",
render: function (data, type, row, meta) {
return new Date(data * 1000).toISOString()
}
},
{
targets: 8,
title: "GitHub",
data: "pkgbase",
render: function (data, type, row, meta) {
return `<a href=https://github.com/archlinuxcn/repo/blob/master/archlinuxcn/${data}/ target=_blank rel=noopener>GitHub</a>`
}
}
]
});
});
</script>
</body>
</html>

View file

@ -2,9 +2,12 @@
extern crate enum_display_derive;
use actix_web::{get, web, App, HttpResponse, HttpServer, Responder};
use anyhow::{Context, Result};
use cached::proc_macro::cached;
use postgres_types::{FromSql, ToSql};
use serde::Serialize;
use std::fmt::Display;
use yaml_rust::YamlLoader;
#[derive(Debug, ToSql, FromSql, Display)]
#[postgres(name = "batchevent")]
@ -54,6 +57,36 @@ struct CurrentResponse {
elapsed: i32,
}
#[derive(Serialize)]
struct LogsResponse {
ts: i64,
pkgbase: String,
pkg_version: String,
maintainer: String,
elapsed: i32,
result: String,
cpu: i32,
memory: f64,
}
#[cached(time = 86400, result = true)]
fn get_maintainer(pkg: String) -> Result<String> {
let contents = std::fs::read_to_string(format!(
"/data/archgitrepo-webhook/archlinuxcn/{}/lilac.yaml",
pkg
))?;
let docs = YamlLoader::load_from_str(&contents)?;
let doc = &docs[0];
let maintainers_yaml = doc["maintainers"]
.as_vec()
.context("maintainers is empty")?;
let mut maintainers: Vec<&str> = vec![];
for m in maintainers_yaml {
maintainers.push(m["github"].as_str().unwrap_or("None"));
}
Ok(maintainers.join(", "))
}
#[get("/imlonghao-api/status")]
async fn status(db: web::Data<deadpool_postgres::Pool>) -> impl Responder {
let conn = db.get().await.unwrap();
@ -102,8 +135,41 @@ async fn current(db: web::Data<deadpool_postgres::Pool>) -> impl Responder {
}
#[get("/imlonghao-api/logs")]
async fn logs() -> impl Responder {
HttpResponse::Ok().body("Todo!")
async fn logs(db: web::Data<deadpool_postgres::Pool>) -> impl Responder {
let conn = db.get().await.unwrap();
let rows = conn
.query(
"select ts, pkgbase, COALESCE(pkg_version, '') AS pkg_version, elapsed, result, COALESCE(case when elapsed = 0 then 0 else cputime * 100 / elapsed end, -1) AS cpu, COALESCE(round(memory / 1073741824.0, 3), -1) AS memory from (
select *, row_number() over (partition by pkgbase order by ts desc) as k
from lilac.pkglog
) as w where k = 1 order by ts desc",
&[],
)
.await
.unwrap();
let mut results: Vec<LogsResponse> = vec![];
for row in rows {
let ts: chrono::DateTime<chrono::Utc> = row.get("ts");
let pkgbase: String = row.get("pkgbase");
let pkg_version: String = row.get("pkg_version");
let maintainer = get_maintainer(pkgbase.clone()).unwrap_or("Unknown".to_string());
let elapsed: i32 = row.get("elapsed");
let result: BuildResult = row.get("result");
let cpu: i32 = row.get("cpu");
let memory: pg_bigdecimal::PgNumeric = row.get("memory");
let memory_bd: bigdecimal::BigDecimal = memory.n.unwrap();
results.push(LogsResponse {
ts: ts.timestamp(),
pkgbase: pkgbase,
pkg_version: pkg_version,
maintainer: maintainer,
elapsed: elapsed,
result: result.to_string(),
cpu: cpu,
memory: memory_bd.to_f64().unwrap(),
})
}
HttpResponse::Ok().json(results)
}
#[actix_web::main]