mirror of
https://github.com/denoland/deno.git
synced 2025-01-11 16:42:21 -05:00
feat(unstable): per op metrics (#9240)
This commit is contained in:
parent
af93256d05
commit
9d70ea2e9f
12 changed files with 126 additions and 56 deletions
24
cli/dts/lib.deno.unstable.d.ts
vendored
24
cli/dts/lib.deno.unstable.d.ts
vendored
|
@ -850,13 +850,13 @@ declare namespace Deno {
|
|||
| "TXT";
|
||||
|
||||
export interface ResolveDnsOptions {
|
||||
/** The name server to be used for lookups.
|
||||
* If not specified, defaults to the system configuration e.g. `/etc/resolv.conf` on Unix. */
|
||||
/** The name server to be used for lookups.
|
||||
* If not specified, defaults to the system configuration e.g. `/etc/resolv.conf` on Unix. */
|
||||
nameServer?: {
|
||||
/** The IP address of the name server */
|
||||
ipAddr: string;
|
||||
/** The port number the query will be sent to.
|
||||
* If not specified, defaults to 53. */
|
||||
* If not specified, defaults to 53. */
|
||||
port?: number;
|
||||
};
|
||||
}
|
||||
|
@ -1343,6 +1343,24 @@ declare namespace Deno {
|
|||
* ```
|
||||
*/
|
||||
export function sleepSync(millis: number): Promise<void>;
|
||||
|
||||
export interface Metrics extends OpMetrics {
|
||||
ops: Record<string, OpMetrics>;
|
||||
}
|
||||
|
||||
export interface OpMetrics {
|
||||
opsDispatched: number;
|
||||
opsDispatchedSync: number;
|
||||
opsDispatchedAsync: number;
|
||||
opsDispatchedAsyncUnref: number;
|
||||
opsCompleted: number;
|
||||
opsCompletedSync: number;
|
||||
opsCompletedAsync: number;
|
||||
opsCompletedAsyncUnref: number;
|
||||
bytesSentControl: number;
|
||||
bytesSentData: number;
|
||||
bytesReceived: number;
|
||||
}
|
||||
}
|
||||
|
||||
declare function fetch(
|
||||
|
|
|
@ -21,7 +21,7 @@ where
|
|||
F: Fn(Rc<RefCell<OpState>>, Value, BufVec) -> R + 'static,
|
||||
R: Future<Output = Result<Value, AnyError>> + 'static,
|
||||
{
|
||||
rt.register_op(name, metrics_op(json_op_async(op_fn)));
|
||||
rt.register_op(name, metrics_op(name, json_op_async(op_fn)));
|
||||
}
|
||||
|
||||
pub fn reg_json_sync<F>(rt: &mut JsRuntime, name: &'static str, op_fn: F)
|
||||
|
@ -29,5 +29,5 @@ where
|
|||
F: Fn(&mut OpState, Value, &mut [ZeroCopyBuf]) -> Result<Value, AnyError>
|
||||
+ 'static,
|
||||
{
|
||||
rt.register_op(name, metrics_op(json_op_sync(op_fn)));
|
||||
rt.register_op(name, metrics_op(name, json_op_sync(op_fn)));
|
||||
}
|
||||
|
|
|
@ -2,30 +2,40 @@
|
|||
import { assert, unitTest } from "./test_util.ts";
|
||||
|
||||
unitTest(async function metrics(): Promise<void> {
|
||||
const m1 = Deno.metrics();
|
||||
assert(m1.opsDispatched > 0);
|
||||
assert(m1.opsDispatchedSync > 0);
|
||||
assert(m1.opsCompleted > 0);
|
||||
assert(m1.opsCompletedSync > 0);
|
||||
assert(m1.bytesSentControl > 0);
|
||||
assert(m1.bytesSentData >= 0);
|
||||
assert(m1.bytesReceived > 0);
|
||||
|
||||
// Write to stdout to ensure a "data" message gets sent instead of just
|
||||
// control messages.
|
||||
const dataMsg = new Uint8Array([13, 13, 13]); // "\r\r\r",
|
||||
await Deno.stdout.write(dataMsg);
|
||||
|
||||
const m1 = Deno.metrics();
|
||||
assert(m1.opsDispatched > 0);
|
||||
assert(m1.opsCompleted > 0);
|
||||
assert(m1.bytesSentControl > 0);
|
||||
assert(m1.bytesSentData >= 0);
|
||||
assert(m1.bytesReceived > 0);
|
||||
const m1OpWrite = m1.ops["op_write"];
|
||||
assert(m1OpWrite.opsDispatchedAsync > 0);
|
||||
assert(m1OpWrite.opsCompletedAsync > 0);
|
||||
assert(m1OpWrite.bytesSentControl > 0);
|
||||
assert(m1OpWrite.bytesSentData >= 0);
|
||||
assert(m1OpWrite.bytesReceived > 0);
|
||||
|
||||
await Deno.stdout.write(dataMsg);
|
||||
|
||||
const m2 = Deno.metrics();
|
||||
assert(m2.opsDispatched > m1.opsDispatched);
|
||||
assert(m2.opsDispatchedSync > m1.opsDispatchedSync);
|
||||
assert(m2.opsDispatchedAsync > m1.opsDispatchedAsync);
|
||||
assert(m2.opsCompleted > m1.opsCompleted);
|
||||
assert(m2.opsCompletedSync > m1.opsCompletedSync);
|
||||
assert(m2.opsCompletedAsync > m1.opsCompletedAsync);
|
||||
assert(m2.bytesSentControl > m1.bytesSentControl);
|
||||
assert(m2.bytesSentData >= m1.bytesSentData + dataMsg.byteLength);
|
||||
assert(m2.bytesReceived > m1.bytesReceived);
|
||||
const m2OpWrite = m2.ops["op_write"];
|
||||
assert(m2OpWrite.opsDispatchedAsync > m1OpWrite.opsDispatchedAsync);
|
||||
assert(m2OpWrite.opsCompletedAsync > m1OpWrite.opsCompletedAsync);
|
||||
assert(m2OpWrite.bytesSentControl > m1OpWrite.bytesSentControl);
|
||||
assert(
|
||||
m2OpWrite.bytesSentData >= m1OpWrite.bytesSentData + dataMsg.byteLength,
|
||||
);
|
||||
assert(m2OpWrite.bytesReceived > m1OpWrite.bytesReceived);
|
||||
});
|
||||
|
||||
unitTest(
|
||||
|
|
|
@ -5,7 +5,11 @@
|
|||
const core = window.Deno.core;
|
||||
|
||||
function metrics() {
|
||||
return core.jsonOpSync("op_metrics");
|
||||
const { combined, ops } = core.jsonOpSync("op_metrics");
|
||||
if (ops) {
|
||||
combined.ops = ops;
|
||||
}
|
||||
return combined;
|
||||
}
|
||||
|
||||
window.__bootstrap.metrics = {
|
||||
|
|
|
@ -1,6 +1,36 @@
|
|||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct Metrics {
|
||||
pub struct RuntimeMetrics {
|
||||
pub ops: HashMap<&'static str, OpMetrics>,
|
||||
}
|
||||
|
||||
impl RuntimeMetrics {
|
||||
pub fn combined_metrics(&self) -> OpMetrics {
|
||||
let mut total = OpMetrics::default();
|
||||
|
||||
for metrics in self.ops.values() {
|
||||
total.ops_dispatched += metrics.ops_dispatched;
|
||||
total.ops_dispatched_sync += metrics.ops_dispatched_sync;
|
||||
total.ops_dispatched_async += metrics.ops_dispatched_async;
|
||||
total.ops_dispatched_async_unref += metrics.ops_dispatched_async_unref;
|
||||
total.ops_completed += metrics.ops_completed;
|
||||
total.ops_completed_sync += metrics.ops_completed_sync;
|
||||
total.ops_completed_async += metrics.ops_completed_async;
|
||||
total.ops_completed_async_unref += metrics.ops_completed_async_unref;
|
||||
total.bytes_sent_control += metrics.bytes_sent_control;
|
||||
total.bytes_sent_data += metrics.bytes_sent_data;
|
||||
total.bytes_received += metrics.bytes_received;
|
||||
}
|
||||
|
||||
total
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct OpMetrics {
|
||||
pub ops_dispatched: u64,
|
||||
pub ops_dispatched_sync: u64,
|
||||
pub ops_dispatched_async: u64,
|
||||
|
@ -14,7 +44,7 @@ pub struct Metrics {
|
|||
pub bytes_received: u64,
|
||||
}
|
||||
|
||||
impl Metrics {
|
||||
impl OpMetrics {
|
||||
fn op_dispatched(
|
||||
&mut self,
|
||||
bytes_sent_control: usize,
|
||||
|
@ -76,9 +106,10 @@ use deno_core::Op;
|
|||
use deno_core::OpFn;
|
||||
use deno_core::OpState;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub fn metrics_op(op_fn: Box<OpFn>) -> Box<OpFn> {
|
||||
pub fn metrics_op(name: &'static str, op_fn: Box<OpFn>) -> Box<OpFn> {
|
||||
Box::new(move |op_state: Rc<RefCell<OpState>>, bufs: BufVec| -> Op {
|
||||
// TODOs:
|
||||
// * The 'bytes' metrics seem pretty useless, especially now that the
|
||||
|
@ -94,7 +125,14 @@ pub fn metrics_op(op_fn: Box<OpFn>) -> Box<OpFn> {
|
|||
|
||||
let op_state_ = op_state.clone();
|
||||
let mut s = op_state.borrow_mut();
|
||||
let metrics = s.borrow_mut::<Metrics>();
|
||||
let runtime_metrics = s.borrow_mut::<RuntimeMetrics>();
|
||||
|
||||
let metrics = if let Some(metrics) = runtime_metrics.ops.get_mut(name) {
|
||||
metrics
|
||||
} else {
|
||||
runtime_metrics.ops.insert(name, OpMetrics::default());
|
||||
runtime_metrics.ops.get_mut(name).unwrap()
|
||||
};
|
||||
|
||||
use deno_core::futures::future::FutureExt;
|
||||
|
||||
|
@ -108,7 +146,8 @@ pub fn metrics_op(op_fn: Box<OpFn>) -> Box<OpFn> {
|
|||
let fut = fut
|
||||
.inspect(move |buf| {
|
||||
let mut s = op_state_.borrow_mut();
|
||||
let metrics = s.borrow_mut::<Metrics>();
|
||||
let runtime_metrics = s.borrow_mut::<RuntimeMetrics>();
|
||||
let metrics = runtime_metrics.ops.get_mut(name).unwrap();
|
||||
metrics.op_completed_async(buf.len());
|
||||
})
|
||||
.boxed_local();
|
||||
|
@ -119,7 +158,8 @@ pub fn metrics_op(op_fn: Box<OpFn>) -> Box<OpFn> {
|
|||
let fut = fut
|
||||
.inspect(move |buf| {
|
||||
let mut s = op_state_.borrow_mut();
|
||||
let metrics = s.borrow_mut::<Metrics>();
|
||||
let runtime_metrics = s.borrow_mut::<RuntimeMetrics>();
|
||||
let metrics = runtime_metrics.ops.get_mut(name).unwrap();
|
||||
metrics.op_completed_async_unref(buf.len());
|
||||
})
|
||||
.boxed_local();
|
||||
|
|
|
@ -105,8 +105,8 @@ lazy_static! {
|
|||
}
|
||||
|
||||
pub fn init(rt: &mut JsRuntime) {
|
||||
rt.register_op("op_read", metrics_op(minimal_op(op_read)));
|
||||
rt.register_op("op_write", metrics_op(minimal_op(op_write)));
|
||||
rt.register_op("op_read", metrics_op("op_read", minimal_op(op_read)));
|
||||
rt.register_op("op_write", metrics_op("op_write", minimal_op(op_write)));
|
||||
super::reg_json_async(rt, "op_shutdown", op_shutdown);
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ pub fn reg_json_async<F, V, R, RV>(
|
|||
R: Future<Output = Result<RV, AnyError>> + 'static,
|
||||
RV: Serialize,
|
||||
{
|
||||
rt.register_op(name, metrics_op(json_op_async(op_fn)));
|
||||
rt.register_op(name, metrics_op(name, json_op_async(op_fn)));
|
||||
}
|
||||
|
||||
pub fn reg_json_sync<F, V, R>(rt: &mut JsRuntime, name: &'static str, op_fn: F)
|
||||
|
@ -57,7 +57,7 @@ where
|
|||
V: DeserializeOwned,
|
||||
R: Serialize,
|
||||
{
|
||||
rt.register_op(name, metrics_op(json_op_sync(op_fn)));
|
||||
rt.register_op(name, metrics_op(name, json_op_sync(op_fn)));
|
||||
}
|
||||
|
||||
/// `UnstableChecker` is a struct so it can be placed inside `GothamState`;
|
||||
|
|
|
@ -126,10 +126,13 @@ impl<'a> plugin_api::Interface for PluginInterface<'a> {
|
|||
_ => unreachable!(),
|
||||
}
|
||||
};
|
||||
self
|
||||
.state
|
||||
.op_table
|
||||
.register_op(name, metrics_op(Box::new(plugin_op_fn)))
|
||||
self.state.op_table.register_op(
|
||||
name,
|
||||
metrics_op(
|
||||
Box::leak(Box::new(name.to_string())),
|
||||
Box::new(plugin_op_fn),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use crate::metrics::Metrics;
|
||||
use crate::metrics::RuntimeMetrics;
|
||||
use crate::ops::UnstableChecker;
|
||||
use crate::permissions::Permissions;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::serde_json;
|
||||
|
@ -42,21 +43,15 @@ fn op_metrics(
|
|||
_args: Value,
|
||||
_zero_copy: &mut [ZeroCopyBuf],
|
||||
) -> Result<Value, AnyError> {
|
||||
let m = state.borrow::<Metrics>();
|
||||
|
||||
Ok(json!({
|
||||
"opsDispatched": m.ops_dispatched,
|
||||
"opsDispatchedSync": m.ops_dispatched_sync,
|
||||
"opsDispatchedAsync": m.ops_dispatched_async,
|
||||
"opsDispatchedAsyncUnref": m.ops_dispatched_async_unref,
|
||||
"opsCompleted": m.ops_completed,
|
||||
"opsCompletedSync": m.ops_completed_sync,
|
||||
"opsCompletedAsync": m.ops_completed_async,
|
||||
"opsCompletedAsyncUnref": m.ops_completed_async_unref,
|
||||
"bytesSentControl": m.bytes_sent_control,
|
||||
"bytesSentData": m.bytes_sent_data,
|
||||
"bytesReceived": m.bytes_received
|
||||
}))
|
||||
let m = state.borrow::<RuntimeMetrics>();
|
||||
let combined = m.combined_metrics();
|
||||
let unstable_checker = state.borrow::<UnstableChecker>();
|
||||
let maybe_ops = if unstable_checker.unstable {
|
||||
Some(&m.ops)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Ok(json!({ "combined": combined, "ops": maybe_ops }))
|
||||
}
|
||||
|
||||
pub fn ppid() -> Value {
|
||||
|
|
|
@ -81,7 +81,7 @@ pub fn init(rt: &mut deno_core::JsRuntime) {
|
|||
super::reg_json_sync(rt, "op_global_timer_stop", op_global_timer_stop);
|
||||
super::reg_json_sync(rt, "op_global_timer_start", op_global_timer_start);
|
||||
super::reg_json_async(rt, "op_global_timer", op_global_timer);
|
||||
rt.register_op("op_now", metrics_op(minimal_op(op_now)));
|
||||
rt.register_op("op_now", metrics_op("op_now", minimal_op(op_now)));
|
||||
super::reg_json_sync(rt, "op_sleep_sync", op_sleep_sync);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::colors;
|
|||
use crate::inspector::DenoInspector;
|
||||
use crate::inspector::InspectorServer;
|
||||
use crate::js;
|
||||
use crate::metrics::Metrics;
|
||||
use crate::metrics::RuntimeMetrics;
|
||||
use crate::ops;
|
||||
use crate::permissions::Permissions;
|
||||
use crate::tokio_util::create_basic_runtime;
|
||||
|
@ -209,9 +209,9 @@ impl WebWorker {
|
|||
{
|
||||
let op_state = js_runtime.op_state();
|
||||
let mut op_state = op_state.borrow_mut();
|
||||
op_state.put::<Metrics>(Default::default());
|
||||
op_state.put(RuntimeMetrics::default());
|
||||
op_state.put::<Permissions>(permissions);
|
||||
op_state.put::<ops::UnstableChecker>(ops::UnstableChecker {
|
||||
op_state.put(ops::UnstableChecker {
|
||||
unstable: options.unstable,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::inspector::DenoInspector;
|
|||
use crate::inspector::InspectorServer;
|
||||
use crate::inspector::InspectorSession;
|
||||
use crate::js;
|
||||
use crate::metrics::Metrics;
|
||||
use crate::metrics::RuntimeMetrics;
|
||||
use crate::ops;
|
||||
use crate::permissions::Permissions;
|
||||
use deno_core::error::AnyError;
|
||||
|
@ -104,9 +104,9 @@ impl MainWorker {
|
|||
{
|
||||
let op_state = js_runtime.op_state();
|
||||
let mut op_state = op_state.borrow_mut();
|
||||
op_state.put::<Metrics>(Default::default());
|
||||
op_state.put(RuntimeMetrics::default());
|
||||
op_state.put::<Permissions>(permissions);
|
||||
op_state.put::<ops::UnstableChecker>(ops::UnstableChecker {
|
||||
op_state.put(ops::UnstableChecker {
|
||||
unstable: options.unstable,
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue