refactor: config log

This commit is contained in:
nathan 2023-03-12 09:18:06 +08:00
parent 7b706b54ce
commit 690ea42d85
15 changed files with 148 additions and 66 deletions

View File

@ -68,11 +68,11 @@ jobs:
- name: Migrate database
run: |
sudo apt-get install libpq-dev -y
SKIP_DOCKER=true POSTGRES_PORT=5433 ./scripts/init_database.sh
SKIP_DOCKER=true POSTGRES_PORT=5433 ./build/init_database.sh
- name: Check sqlx-data.json is up-to-date
run: |
cargo sqlx prepare --check -- --bin http_server
cargo sqlx prepare --check -- --bin appflowy_server
- name: Run cargo test
run: cargo test
@ -140,7 +140,7 @@ jobs:
- name: Migrate database
run: |
sudo apt-get install libpq-dev -y
SKIP_DOCKER=true POSTGRES_PORT=5433 ./scripts/init_database.sh
SKIP_DOCKER=true POSTGRES_PORT=5433 ./build/init_database.sh
- run: rustup component add clippy
- run: cargo clippy -- -D warnings

38
Cargo.lock generated
View File

@ -401,9 +401,9 @@ dependencies = [
"sqlx",
"tokio",
"tracing",
"tracing-appender",
"tracing-actix-web",
"tracing-bunyan-formatter",
"tracing-futures",
"tracing-log",
"tracing-subscriber",
]
@ -2137,7 +2137,7 @@ dependencies = [
"thiserror",
"tokio-stream",
"url",
"uuid",
"uuid 0.8.2",
"whoami",
]
@ -2388,14 +2388,15 @@ dependencies = [
]
[[package]]
name = "tracing-appender"
version = "0.2.2"
name = "tracing-actix-web"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09d48f71a791638519505cefafe162606f706c25592e4bde4d97600c0195312e"
checksum = "4082e4d81173e0b7ad3cfb71e9eaef0dd0cbb7b139fdb56394f488a3b0760b23"
dependencies = [
"crossbeam-channel",
"time 0.3.20",
"tracing-subscriber",
"actix-web",
"pin-project",
"tracing",
"uuid 1.3.0",
]
[[package]]
@ -2437,16 +2438,6 @@ dependencies = [
"valuable",
]
[[package]]
name = "tracing-futures"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2"
dependencies = [
"pin-project",
"tracing",
]
[[package]]
name = "tracing-log"
version = "0.1.3"
@ -2567,6 +2558,15 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
[[package]]
name = "uuid"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79"
dependencies = [
"getrandom",
]
[[package]]
name = "valuable"
version = "0.1.0"

View File

@ -36,10 +36,10 @@ derive_more = {version = "0.99"}
# tracing
tracing = { version = "0.1.37" }
tracing-futures = "0.2.5"
tracing-subscriber = { version = "0.3.16", features = ["registry", "env-filter", "ansi", "json"] }
tracing-bunyan-formatter = "0.3.6"
tracing-appender = "0.2.2"
tracing-actix-web = "0.7"
tracing-log = "0.1.1"
ormx = { version = "0.10.0", features = ["postgres"]}
[dependencies.sqlx]
@ -56,7 +56,7 @@ features = [
]
[[bin]]
name = "http_server"
name = "appflowy_server"
path = "src/main.rs"

View File

@ -2,11 +2,11 @@ FROM rust:1.56.1 as builder
WORKDIR /app
COPY . .
WORKDIR /app/services/http_server
WORKDIR /app/services/appflowy_server
ENV SQLX_OFFLINE true
RUN RUSTFLAGS="-C opt-level=2" cargo build --release --bin http_server
RUN RUSTFLAGS="-C opt-level=2" cargo build --release --bin appflowy_server
# Size optimization
#RUN strip ./target/release/http_server
#RUN strip ./target/release/appflowy_server
FROM debian:bullseye-slim AS runtime
WORKDIR /app
@ -17,7 +17,7 @@ RUN apt-get update -y \
&& apt-get clean -y \
&& rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/services/target/release/http_server /usr/local/bin/http_server
COPY --from=builder /app/services/http_server/configuration configuration
COPY --from=builder /app/services/target/release/appflowy_server /usr/local/bin/appflowy_server
COPY --from=builder /app/services/appflowy_server/configuration configuration
ENV APP_ENVIRONMENT production
CMD ["http_server"]
CMD ["appflowy_server"]

View File

@ -1,4 +1,4 @@
ROOT = "./scripts"
ROOT = "./build"
SEMVER_VERSION=$(shell grep version Cargo.toml | awk -F"\"" '{print $$2}' | head -n 1)
.PHONY: init_database docker_image local_server docker_test
@ -8,7 +8,7 @@ init_database:
docker_image:
source $(ROOT)/docker_env.sh && docker-compose up -d postgres_db
source $(ROOT)/docker_env.sh && docker-compose up -d http_server
source $(ROOT)/docker_env.sh && docker-compose up -d appflowy_server
local_server:
cargo run

View File

@ -8,15 +8,15 @@ services:
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
ports:
- "5434:5432"
http_server:
appflowy_server:
restart: on-failure
environment:
- APP_ENVIRONMENT=production
- DATABASE_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db/${POSTGRES_DB}"
build:
context: ../../
dockerfile: ./services/http_server/Dockerfile
image: http_server:${BACKEND_VERSION}
dockerfile: ./services/appflowy_server/Dockerfile
image: appflowy_server:${BACKEND_VERSION}
depends_on:
- postgres_db
ports:

View File

@ -3,10 +3,11 @@ use actix_web::{dev::Server, middleware, web, web::Data, App, HttpServer};
use sqlx::{postgres::PgPoolOptions, PgPool};
use std::net::TcpListener;
use std::sync::Arc;
use tracing_actix_web::TracingLogger;
use crate::api::{token_scope, user_scope};
use crate::config::config::{Config, DatabaseSettings};
use crate::config::config::{Config, DatabaseSetting};
use crate::config::env::{domain, secret};
use crate::middleware::cors::default_cors;
use crate::state::State;
@ -46,6 +47,7 @@ pub fn run(listener: TcpListener, state: State) -> Result<Server, std::io::Error
.wrap(middleware::Logger::default())
.wrap(IdentityMiddleware::default())
.wrap(default_cors())
.wrap(TracingLogger::default())
.app_data(web::JsonConfig::default().limit(4096))
.service(user_scope())
.service(token_scope())
@ -72,7 +74,7 @@ pub async fn init_state(configuration: &Config) -> State {
}
}
pub async fn get_connection_pool(setting: &DatabaseSettings) -> Result<PgPool, sqlx::Error> {
pub async fn get_connection_pool(setting: &DatabaseSetting) -> Result<PgPool, sqlx::Error> {
PgPoolOptions::new()
.connect_timeout(std::time::Duration::from_secs(5))
.connect_with(setting.with_db())

View File

@ -1,22 +0,0 @@
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
use tracing_subscriber::EnvFilter;
pub fn init_log() {
if std::env::var_os("RUST_LOG").is_none() {
std::env::set_var("RUST_LOG", "debug");
}
let subscriber = tracing_subscriber::fmt()
.with_target(true)
.with_max_level(tracing::Level::TRACE)
.with_writer(std::io::stderr)
.with_thread_ids(true)
.compact()
.finish()
.with(EnvFilter::from_default_env());
// let formatting_layer = BunyanFormattingLayer::new(self.name, std::io::stdout);
// set_global_default(subscriber.with(JsonStorageLayer).with(formatting_layer)).map_err(|e| format!("{:?}", e))?;
subscriber.try_init().unwrap()
}

View File

@ -1 +1 @@
pub mod log;

View File

@ -5,7 +5,7 @@ use std::convert::{TryFrom, TryInto};
#[derive(serde::Deserialize, Clone, Debug)]
pub struct Config {
pub database: DatabaseSettings,
pub database: DatabaseSetting,
pub application: ApplicationSettings,
}
@ -25,7 +25,7 @@ pub struct ApplicationSettings {
}
#[derive(serde::Deserialize, Clone, Debug)]
pub struct DatabaseSettings {
pub struct DatabaseSetting {
pub username: String,
pub password: String,
#[serde(deserialize_with = "deserialize_number_from_string")]
@ -35,7 +35,7 @@ pub struct DatabaseSettings {
pub require_ssl: bool,
}
impl DatabaseSettings {
impl DatabaseSetting {
pub fn without_db(&self) -> PgConnectOptions {
let ssl_mode = if self.require_ssl {
PgSslMode::Require

View File

@ -4,3 +4,4 @@ pub mod component;
pub mod config;
pub mod middleware;
pub mod state;
pub mod telemetry;

View File

@ -1,10 +1,12 @@
use appflowy_server::application::{init_state, Application};
use appflowy_server::component::log::init_log;
use appflowy_server::config::config::get_configuration;
use appflowy_server::telemetry::{get_subscriber, init_subscriber};
#[actix_web::main]
async fn main() -> std::io::Result<()> {
init_log();
let subscriber = get_subscriber("appflowy_server".into(), "info".into(), std::io::stdout);
init_subscriber(subscriber);
let configuration = get_configuration().expect("Failed to read configuration.");
let state = init_state(&configuration).await;
let application = Application::build(configuration, state).await?;

42
src/telemetry.rs Normal file
View File

@ -0,0 +1,42 @@
use actix_web::rt::task::JoinHandle;
use tracing::subscriber::set_global_default;
use tracing::Subscriber;
use tracing_bunyan_formatter::{BunyanFormattingLayer, JsonStorageLayer};
use tracing_log::LogTracer;
use tracing_subscriber::fmt::MakeWriter;
use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Registry};
/// Compose multiple layers into a `tracing`'s subscriber.
pub fn get_subscriber<Sink>(
name: String,
env_filter: String,
sink: Sink,
) -> impl Subscriber + Sync + Send
where
Sink: for<'a> MakeWriter<'a> + Send + Sync + 'static,
{
let env_filter =
EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new(env_filter));
let formatting_layer = BunyanFormattingLayer::new(name, sink);
Registry::default()
.with(env_filter)
.with(JsonStorageLayer)
.with(formatting_layer)
}
/// Register a subscriber as global default to process span data.
///
/// It should only be called once!
pub fn init_subscriber(subscriber: impl Subscriber + Sync + Send) {
LogTracer::init().expect("Failed to set logger");
set_global_default(subscriber).expect("Failed to set subscriber");
}
pub fn spawn_blocking_with_tracing<F, R>(f: F) -> JoinHandle<R>
where
F: FnOnce() -> R + Send + 'static,
R: Send + 'static,
{
let current_span = tracing::Span::current();
actix_web::rt::task::spawn_blocking(move || current_span.in_scope(f))
}

1
tests/api/main.rs Normal file
View File

@ -0,0 +1 @@
mod test_server;

56
tests/api/test_server.rs Normal file
View File

@ -0,0 +1,56 @@
use appflowy_server::application::{init_state, Application};
use appflowy_server::config::config::{get_configuration, DatabaseSetting};
use appflowy_server::state::State;
use sqlx::types::Uuid;
use sqlx::{Connection, Executor, PgConnection, PgPool};
#[derive(Clone)]
pub struct TestServer {
pub state: State,
}
pub async fn spawn_server() -> TestServer {
let database_name = Uuid::new_v4().to_string();
let configuration = {
let mut c = get_configuration().expect("Failed to read configuration.");
c.database.database_name = database_name.clone();
// Use a random OS port
c.application.port = 0;
c
};
let _ = configure_database(&configuration.database).await;
let state = init_state(&configuration).await;
let application = Application::build(configuration.clone(), state.clone())
.await
.expect("Failed to build application.");
let _ = tokio::spawn(async {
let _ = application.run_until_stopped();
});
TestServer { state }
}
async fn configure_database(config: &DatabaseSetting) -> PgPool {
// Create database
let mut connection = PgConnection::connect_with(&config.without_db())
.await
.expect("Failed to connect to Postgres");
connection
.execute(&*format!(r#"CREATE DATABASE "{}";"#, config.database_name))
.await
.expect("Failed to create database.");
// Migrate database
let connection_pool = PgPool::connect_with(config.with_db())
.await
.expect("Failed to connect to Postgres.");
sqlx::migrate!("./migrations")
.run(&connection_pool)
.await
.expect("Failed to migrate the database");
connection_pool
}