Skip to content

Commit 39c856a

Browse files
authored
feat: Ingestion traces (#1629)
* add traces to ingestion * fix: disjointed traces * modify cli * make push_logs sync and try ControlFlow * further improvements * diskwriter change * cargo fmt * revert back to MergedReverseRecordReader * fix: cargo clippy * fix: clippy and coderabbit suggestions
1 parent eb0e5f2 commit 39c856a

17 files changed

Lines changed: 680 additions & 328 deletions

File tree

Cargo.toml

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,10 @@ base64 = "0.22.0"
6363
cookie = "0.18.1"
6464
hex = "0.4"
6565
openid = { version = "0.18.3", default-features = false, features = ["rustls"] }
66-
rustls = { version = "0.23", default-features = false, features = ["ring", "std"] }
66+
rustls = { version = "0.23", default-features = false, features = [
67+
"ring",
68+
"std",
69+
] }
6770
rustls-pemfile = "2.1.2"
6871
sha2 = "0.10.8"
6972

@@ -104,10 +107,27 @@ opentelemetry-proto = { git = "https://github.com/open-telemetry/opentelemetry-r
104107
"metrics",
105108
"trace",
106109
] }
107-
prometheus = { version = "0.13.4", default-features = false, features = ["process"] }
110+
prometheus = { version = "0.13.4", default-features = false, features = [
111+
"process",
112+
] }
108113
prometheus-parse = "0.2.5"
109-
tracing = "0.1"
110-
tracing-subscriber = { version = "0.3", features = ["env-filter", "time"] }
114+
tracing = "0.1.44"
115+
tracing-subscriber = { version = "0.3.23", features = [
116+
"env-filter",
117+
"time",
118+
"registry",
119+
] }
120+
121+
# telemetry
122+
tracing-opentelemetry = "0.32.1"
123+
opentelemetry = "0.31.0"
124+
opentelemetry_sdk = { version = "0.31.0", features = ["rt-tokio"] }
125+
opentelemetry-otlp = { version = "0.31.1", features = [
126+
"grpc-tonic",
127+
"http-proto",
128+
"http-json",
129+
] }
130+
tracing-actix-web = "0.7"
111131

112132
# Time and Date
113133
chrono = "0.4"

src/cli.rs

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
*
1717
*/
1818

19-
use clap::Parser;
19+
use clap::{Parser, value_parser};
2020
use std::{env, fs, path::PathBuf};
2121

2222
use url::Url;
@@ -148,6 +148,52 @@ pub struct Options {
148148
)]
149149
pub address: String,
150150

151+
// Actix request timeout in seconds
152+
#[arg(
153+
long,
154+
env = "P_ACTIX_REQUEST_TIMEOUT",
155+
default_value = "5",
156+
help = "Client request timeout"
157+
)]
158+
pub request_timeout: u64,
159+
160+
// Actix keep alive in seconds
161+
#[arg(
162+
long,
163+
env = "P_ACTIX_KEEP_ALIVE",
164+
default_value = "5",
165+
help = "Server keep-alive"
166+
)]
167+
pub keep_alive: u64,
168+
169+
// Actix num workers
170+
#[arg(
171+
long,
172+
env = "P_ACTIX_NUM_WORKERS",
173+
default_value_t = num_cpus::get() as u64,
174+
value_parser = value_parser!(u64).range(1..),
175+
help = "Number of workers for actix-web"
176+
)]
177+
pub num_workers: u64,
178+
179+
// Actix connections backlog
180+
#[arg(
181+
long,
182+
env = "P_ACTIX_BACKLOG",
183+
default_value = "2048",
184+
help = "Maximum number of pending connections"
185+
)]
186+
pub connection_backlog: u32,
187+
188+
// Actix max connections
189+
#[arg(
190+
long,
191+
env = "P_ACTIX_MAX_CONNECTIONS",
192+
default_value = "25000",
193+
help = "Per-worker maximum number of concurrent connections"
194+
)]
195+
pub max_connections: usize,
196+
151197
#[arg(
152198
long = "origin",
153199
env = "P_ORIGIN_URI",

src/event/format/json.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use std::{
3131
collections::{HashMap, HashSet},
3232
sync::Arc,
3333
};
34-
use tracing::error;
34+
use tracing::{error, info_span};
3535

3636
use super::EventFormat;
3737
use super::{detect_schema_conflicts, rename_conflicting_fields_in_json};
@@ -86,8 +86,12 @@ impl EventFormat for Event {
8686
// IMPORTANT: Detect conflicts BEFORE update_field_type_in_schema, because
8787
// update_field_type_in_schema may override types (e.g., force Utf8 to Timestamp
8888
// if existing schema has Timestamp), which would hide the actual conflict.
89-
let raw_inferred_schema = infer_json_schema_from_iterator(value_arr.iter().map(Ok))
90-
.map_err(|err| anyhow!("Could not infer schema for this event due to err {:?}", err))?;
89+
let raw_inferred_schema = {
90+
let _span = info_span!("infer_json_schema", record_count = value_arr.len()).entered();
91+
infer_json_schema_from_iterator(value_arr.iter().map(Ok)).map_err(|err| {
92+
anyhow!("Could not infer schema for this event due to err {:?}", err)
93+
})?
94+
};
9195

9296
// Detect schema conflicts using raw inferred schema vs existing stream schema
9397
// Pass the actual values and schema_version to check if values can be coerced to existing types
@@ -110,7 +114,11 @@ impl EventFormat for Event {
110114
collect_keys(value_arr.iter()).expect("fields can be collected from array of objects");
111115

112116
let mut is_first = false;
113-
let (value_arr, schema) = match derive_arrow_schema(stream_schema, fields) {
117+
let res = {
118+
let _span = info_span!("derive_arrow_schema").entered();
119+
derive_arrow_schema(stream_schema, fields)
120+
};
121+
let (value_arr, schema) = match res {
114122
Ok(schema) => (value_arr, schema),
115123
Err(_) => {
116124
let mut infer_schema = infer_json_schema_from_iterator(value_arr.iter().map(Ok))
@@ -155,6 +163,7 @@ impl EventFormat for Event {
155163

156164
// Convert the Data type (defined above) to arrow record batch
157165
fn decode(data: Self::Data, schema: Arc<Schema>) -> Result<RecordBatch, anyhow::Error> {
166+
let _span = info_span!("json_to_recordbatch", record_count = data.len()).entered();
158167
let array_capacity = round_upto_multiple_of_64(data.len());
159168
let mut reader = ReaderBuilder::new(schema)
160169
.with_batch_size(array_capacity)

src/event/format/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ use arrow_schema::{DataType, Field, Schema, TimeUnit};
2929
use chrono::{DateTime, Utc};
3030
use serde::{Deserialize, Serialize};
3131
use serde_json::Value;
32+
use tracing::info_span;
3233

3334
use crate::{
3435
handlers::TelemetryType,
@@ -167,6 +168,7 @@ pub trait EventFormat: Sized {
167168
schema_version: SchemaVersion,
168169
p_custom_fields: &HashMap<String, String>,
169170
) -> Result<(RecordBatch, bool), AnyError> {
171+
let _span = info_span!("into_recordbatch").entered();
170172
let p_timestamp = self.get_p_timestamp();
171173
let (data, schema, is_first) = self.to_data(
172174
storage_schema,

src/event/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ use arrow_schema::{Field, Fields, Schema};
2424
use itertools::Itertools;
2525
use std::sync::Arc;
2626

27+
use tracing::{info_span, instrument};
28+
2729
use self::error::EventError;
2830
use crate::{
2931
LOCK_EXPECT,
@@ -60,6 +62,16 @@ pub struct Event {
6062

6163
// Events holds the schema related to a each event for a single log stream
6264
impl Event {
65+
#[instrument(
66+
name = "event_process",
67+
level = "info",
68+
skip_all,
69+
fields(
70+
stream_name = %self.stream_name,
71+
num_rows = self.rb.num_rows(),
72+
is_first_event = self.is_first_event
73+
)
74+
)]
6375
pub fn process(self) -> Result<(), EventError> {
6476
let mut key = get_schema_key(&self.rb.schema().fields);
6577
if self.time_partition.is_some() {
@@ -144,6 +156,7 @@ pub fn commit_schema(
144156
schema: Arc<Schema>,
145157
tenant_id: &Option<String>,
146158
) -> Result<(), StagingError> {
159+
let _span = info_span!("commit_schema", stream_name).entered();
147160
let mut stream_metadata = PARSEABLE.streams.write().expect("lock poisoned");
148161
let tenant_id = tenant_id.as_deref().unwrap_or(DEFAULT_TENANT);
149162
let map = &mut stream_metadata

src/handlers/http/modal/mod.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@
1616
*
1717
*/
1818

19-
use std::{fmt, path::Path, sync::Arc};
19+
use std::{fmt, path::Path, sync::Arc, time::Duration};
2020

21-
use actix_web::{App, HttpServer, middleware::from_fn, web::ServiceConfig};
21+
use actix_web::{App, HttpServer, http::KeepAlive, middleware::from_fn, web::ServiceConfig};
2222
use actix_web_prometheus::PrometheusMetrics;
2323
use anyhow::Context;
24+
use arrow::datatypes::ArrowNativeType;
2425
use async_trait::async_trait;
2526
use base64::{Engine, prelude::BASE64_STANDARD};
2627
use bytes::Bytes;
@@ -121,8 +122,22 @@ pub trait ParseableServer {
121122

122123
// Create the HTTP server
123124
let http_server = HttpServer::new(create_app_fn)
124-
.workers(num_cpus::get())
125+
.workers(PARSEABLE.options.num_workers.as_usize())
126+
.keep_alive(KeepAlive::Timeout(Duration::from_secs(
127+
PARSEABLE.options.keep_alive,
128+
)))
129+
.client_request_timeout(Duration::from_secs(PARSEABLE.options.request_timeout))
130+
.backlog(PARSEABLE.options.connection_backlog)
131+
.max_connections(PARSEABLE.options.max_connections)
125132
.shutdown_timeout(60);
133+
tracing::warn!(
134+
"Starting Query server with-\nNum workers: {}\nKeep Alive: {}\nRequest timeout: {}\nConnection backlog: {}\nMax connections: {}",
135+
PARSEABLE.options.num_workers,
136+
PARSEABLE.options.keep_alive,
137+
PARSEABLE.options.request_timeout,
138+
PARSEABLE.options.connection_backlog,
139+
PARSEABLE.options.max_connections
140+
);
126141

127142
// Start the server with or without TLS
128143
let srv = if let Some(config) = ssl {

0 commit comments

Comments
 (0)