Skip to content

Commit

Permalink
Optimize the Response data
Browse files Browse the repository at this point in the history
  • Loading branch information
photino committed Oct 20, 2023
1 parent a4393b9 commit 79b4fef
Show file tree
Hide file tree
Showing 13 changed files with 318 additions and 101 deletions.
5 changes: 5 additions & 0 deletions examples/actix-app/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
#![allow(async_fn_in_trait)]
#![allow(stable_features)]
#![feature(async_fn_in_trait)]
#![feature(lazy_cell)]

mod controller;
mod domain;
mod extension;
Expand Down
2 changes: 2 additions & 0 deletions examples/actix-app/src/model/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
pub(crate) mod tag;

pub(crate) use tag::Tag;
77 changes: 77 additions & 0 deletions examples/actix-app/src/model/tag.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
use serde::{Deserialize, Serialize};
use zino_core::{
datetime::DateTime, extension::JsonObjectExt, model::Model, request::Validation, Map, Uuid,
};
use zino_derive::{ModelAccessor, ModelHooks, Schema};

/// The `tag` model.
#[derive(Debug, Clone, Default, Serialize, Deserialize, Schema, ModelAccessor, ModelHooks)]
#[serde(rename_all = "snake_case")]
#[serde(default)]
pub struct Tag {
// Basic fields.
#[schema(readonly)]
id: Uuid,
#[schema(not_null, index_type = "text")]
name: String,
#[cfg(feature = "namespace")]
#[schema(default_value = "Tag::model_namespace", index_type = "hash")]
namespace: String,
#[schema(default_value = "Active", index_type = "hash")]
status: String,
#[schema(index_type = "text")]
description: String,

// Info fields.
#[schema(not_null)]
category: String,
#[schema(reference = "Tag")]
parent_id: Option<Uuid>, // tag.id, tag.namespace = {tag.namespace}, tag.category = {tag.category}

// Extensions.
content: Map,
extra: Map,

// Revisions.
#[schema(readonly, default_value = "now", index_type = "btree")]
created_at: DateTime,
#[schema(default_value = "now", index_type = "btree")]
updated_at: DateTime,
version: u64,
}

impl Model for Tag {
#[inline]
fn new() -> Self {
Self {
id: Uuid::new_v4(),
..Self::default()
}
}

fn read_map(&mut self, data: &Map) -> Validation {
let mut validation = Validation::new();
if let Some(result) = data.parse_uuid("id") {
match result {
Ok(id) => self.id = id,
Err(err) => validation.record_fail("id", err),
}
}
if let Some(name) = data.parse_string("name") {
self.name = name.into_owned();
}
if let Some(description) = data.parse_string("description") {
self.description = description.into_owned();
}
if let Some(category) = data.parse_string("category") {
self.category = category.into_owned();
}
if let Some(result) = data.parse_uuid("parent_id") {
match result {
Ok(parent_id) => self.parent_id = Some(parent_id),
Err(err) => validation.record_fail("parent_id", err),
}
}
validation
}
}
3 changes: 2 additions & 1 deletion examples/actix-app/src/router/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use crate::{
controller::{auth, file, stats, task, user},
middleware,
model::Tag,
};
use actix_web::web::{get, post, scope, ServiceConfig};
use zino::{DefaultController, RouterConfigure};
use zino_model::{Tag, User};
use zino_model::User;

pub fn routes() -> Vec<RouterConfigure> {
vec![
Expand Down
5 changes: 5 additions & 0 deletions examples/axum-app/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
#![allow(async_fn_in_trait)]
#![allow(stable_features)]
#![feature(async_fn_in_trait)]
#![feature(lazy_cell)]

mod controller;
mod domain;
mod extension;
Expand Down
2 changes: 2 additions & 0 deletions examples/axum-app/src/model/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
pub(crate) mod tag;

pub(crate) use tag::Tag;
77 changes: 77 additions & 0 deletions examples/axum-app/src/model/tag.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
use serde::{Deserialize, Serialize};
use zino_core::{
datetime::DateTime, extension::JsonObjectExt, model::Model, request::Validation, Map, Uuid,
};
use zino_derive::{ModelAccessor, ModelHooks, Schema};

/// The `tag` model.
#[derive(Debug, Clone, Default, Serialize, Deserialize, Schema, ModelAccessor, ModelHooks)]
#[serde(rename_all = "snake_case")]
#[serde(default)]
pub struct Tag {
// Basic fields.
#[schema(readonly)]
id: Uuid,
#[schema(not_null, index_type = "text")]
name: String,
#[cfg(feature = "namespace")]
#[schema(default_value = "Tag::model_namespace", index_type = "hash")]
namespace: String,
#[schema(default_value = "Active", index_type = "hash")]
status: String,
#[schema(index_type = "text")]
description: String,

// Info fields.
#[schema(not_null)]
category: String,
#[schema(reference = "Tag")]
parent_id: Option<Uuid>, // tag.id, tag.namespace = {tag.namespace}, tag.category = {tag.category}

// Extensions.
content: Map,
extra: Map,

// Revisions.
#[schema(readonly, default_value = "now", index_type = "btree")]
created_at: DateTime,
#[schema(default_value = "now", index_type = "btree")]
updated_at: DateTime,
version: u64,
}

impl Model for Tag {
#[inline]
fn new() -> Self {
Self {
id: Uuid::new_v4(),
..Self::default()
}
}

fn read_map(&mut self, data: &Map) -> Validation {
let mut validation = Validation::new();
if let Some(result) = data.parse_uuid("id") {
match result {
Ok(id) => self.id = id,
Err(err) => validation.record_fail("id", err),
}
}
if let Some(name) = data.parse_string("name") {
self.name = name.into_owned();
}
if let Some(description) = data.parse_string("description") {
self.description = description.into_owned();
}
if let Some(category) = data.parse_string("category") {
self.category = category.into_owned();
}
if let Some(result) = data.parse_uuid("parent_id") {
match result {
Ok(parent_id) => self.parent_id = Some(parent_id),
Err(err) => validation.record_fail("parent_id", err),
}
}
validation
}
}
3 changes: 2 additions & 1 deletion examples/axum-app/src/router/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::{
controller::{auth, file, stats, task, user},
model::Tag,
middleware,
};
use axum::{
Expand All @@ -8,7 +9,7 @@ use axum::{
Router,
};
use zino::DefaultController;
use zino_model::{Tag, User};
use zino_model::User;

pub fn routes() -> Vec<Router> {
let mut routes = Vec::new();
Expand Down
6 changes: 2 additions & 4 deletions zino-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ reqwest-middleware = "0.2.3"
reqwest-retry = "0.3.0"
reqwest-tracing = "0.4.6"
rmp-serde = "1.1.2"
serde_json = "1.0.107"
serde_qs = "0.12.0"
sha2 = "0.10.8"
sysinfo = "0.29.10"
Expand Down Expand Up @@ -241,10 +242,6 @@ features = [
version = "1.0.189"
features = ["derive"]

[dependencies.serde_json]
version = "1.0.107"
features = ["raw_value"]

[dependencies.sm3]
version = "0.4.2"
optional = true
Expand Down Expand Up @@ -310,6 +307,7 @@ data-encoding = "2.4.0"
libsm = "0.5.1"
ryu = "1.0.15"
sm3 = "0.4.2"
sonic-rs = "0.1.3"
tinyvec = { version = "1.6.0", features = ["alloc"] }
uuid-simd = "0.8.0"

Expand Down
14 changes: 14 additions & 0 deletions zino-core/benches/json_raw_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,18 @@ pub fn bench(c: &mut criterion::Criterion) {
serde_json::to_vec(&res)
})
});
c.bench_function("sonic_serialize_json_object", |b| {
b.iter(|| {
let mut res = Map::new();
res.upsert("status_code", 200);
res.upsert("request_id", Uuid::new_v4().to_string());

let mut data = Map::new();
data.upsert("name", "alice");
data.upsert("age", 18);
data.upsert("roles", vec!["admin", "worker"]);
res.upsert("data", data);
sonic_rs::to_vec(&res)
})
});
}
116 changes: 89 additions & 27 deletions zino-core/src/application/http_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,36 +178,84 @@ struct RequestTiming;

impl ReqwestOtelSpanBackend for RequestTiming {
fn on_request_start(request: &Request, extensions: &mut Extensions) -> Span {
let method = request.method();

// URL
let url = request.url();
let scheme = url.scheme();
let host = url.host_str();
let port = url.port();
let path = url.path();
let query = url.query();
let full_url = remove_credentials(&url);

// Headers
let headers = request.headers();
let traceparent = headers.get_str("traceparent");
let tracestate = headers.get_str("tracestate");
let trace_context = traceparent.and_then(TraceContext::from_traceparent);
let session_id = headers.get_str("session-id");
let trace_id = trace_context
.as_ref()
.map(|ctx| Uuid::from_u128(ctx.trace_id()).to_string());
let parent_id = trace_context
.and_then(|ctx| ctx.parent_id())
.map(|parent_id| format!("{parent_id:x}"));

extensions.insert(Instant::now());
tracing::info_span!(
"HTTP request",
"otel.kind" = "client",
"otel.name" = "zino-bot",
"http.scheme" = url.scheme(),
"http.method" = request.method().as_str(),
"http.url" = remove_credentials(url).as_ref(),
"http.request.header.traceparent" = traceparent,
"http.request.header.tracestate" = headers.get_str("tracestate"),
"http.response.header.traceparent" = Empty,
"http.response.header.tracestate" = Empty,
"http.status_code" = Empty,
"http.client.duration" = Empty,
"net.peer.name" = url.domain(),
"net.peer.port" = url.port(),
"context.request_id" = Empty,
"context.session_id" = headers.get_str("session-id"),
"context.span_id" = Empty,
"context.trace_id" = trace_context
.as_ref()
.map(|ctx| Uuid::from_u128(ctx.trace_id()).to_string()),
"context.parent_id" = trace_context
.and_then(|ctx| ctx.parent_id())
.map(|parent_id| format!("{parent_id:x}")),
)
if method.is_safe() {
tracing::info_span!(
"HTTP request",
"otel.kind" = "client",
"otel.name" = "zino-bot",
"otel.status_code" = Empty,
"url.scheme" = scheme,
"url.path" = path,
"url.query" = query,
"url.full" = full_url.as_ref(),
"http.request.method" = method.as_str(),
"http.request.header.traceparent" = traceparent,
"http.request.header.tracestate" = tracestate,
"http.response.header.traceparent" = Empty,
"http.response.header.tracestate" = Empty,
"http.response.header.server_timing" = Empty,
"http.response.status_code" = Empty,
"http.client.duration" = Empty,
"server.address" = host,
"server.port" = port,
"context.session_id" = session_id,
"context.trace_id" = trace_id,
"context.request_id" = Empty,
"context.span_id" = Empty,
"context.parent_id" = parent_id,
)
} else {
tracing::warn_span!(
"HTTP request",
"otel.kind" = "client",
"otel.name" = "zino-bot",
"otel.status_code" = Empty,
"url.scheme" = scheme,
"url.path" = path,
"url.query" = query,
"url.full" = full_url.as_ref(),
"http.request.method" = method.as_str(),
"http.request.header.traceparent" = traceparent,
"http.request.header.tracestate" = tracestate,
"http.response.header.traceparent" = Empty,
"http.response.header.tracestate" = Empty,
"http.response.header.server_timing" = Empty,
"http.response.status_code" = Empty,
"http.client.duration" = Empty,
"server.address" = host,
"server.port" = port,
"context.session_id" = session_id,
"context.trace_id" = trace_id,
"context.request_id" = Empty,
"context.span_id" = Empty,
"context.parent_id" = parent_id,
)
}
}

fn on_request_end(
Expand All @@ -234,15 +282,29 @@ impl ReqwestOtelSpanBackend for RequestTiming {
"http.response.header.tracestate",
headers.get_str("tracestate"),
);
span.record(
"http.response.header.server_timing",
headers.get_str("server-timing"),
);
span.record("context.request_id", headers.get_str("x-request-id"));
span.record("http.status_code", response.status().as_u16());
span.record("http.response.status_code", response.status().as_u16());
span.record("otel.status_code", "OK");
tracing::info!("finished HTTP request");
}
Err(err) => {
if let reqwest_middleware::Error::Reqwest(err) = err {
if let Some(status_code) = err.status() {
span.record("http.status_code", status_code.as_u16());
span.record("http.response.status_code", status_code.as_u16());
if status_code.is_server_error() {
span.record("otel.status_code", "OK");
} else {
span.record("otel.status_code", "ERROR");
}
} else {
span.record("otel.status_code", "ERROR");
}
} else {
span.record("otel.status_code", "ERROR");
}
tracing::error!("{err}");
}
Expand Down
Loading

0 comments on commit 79b4fef

Please sign in to comment.