Skip to main content

trojan_analytics/
lib.rs

1//! Analytics module for trojan-rs.
2//!
3//! This module provides detailed connection event collection and export to ClickHouse
4//! for traffic analysis, billing, and auditing.
5//!
6//! # Feature Gating
7//!
8//! This crate should be used with the `analytics` feature in `trojan-server`:
9//!
10//! ```toml
11//! [features]
12//! analytics = ["trojan-analytics"]
13//! ```
14//!
15//! # Example
16//!
17//! ```ignore
18//! use trojan_analytics::{EventCollector, init};
19//! use trojan_config::AnalyticsConfig;
20//!
21//! // Initialize analytics
22//! let collector = init(config).await?;
23//!
24//! // Record connection events
25//! let event = collector.connection(conn_id, peer)
26//!     .user("user123")
27//!     .target("example.com", 443, TargetType::Domain)
28//!     .protocol(Protocol::Tcp);
29//!
30//! // Event is automatically sent on drop
31//! ```
32
33mod collector;
34mod error;
35mod event;
36mod writer;
37
38pub use collector::{ConnectionEventBuilder, EventCollector};
39pub use error::AnalyticsError;
40pub use event::*;
41pub use trojan_config::{
42    AnalyticsBufferConfig, AnalyticsConfig, AnalyticsPrivacyConfig, AnalyticsSamplingConfig,
43    ClickHouseConfig,
44};
45
46use std::sync::Arc;
47use tokio::sync::mpsc;
48use tracing::info;
49
50/// Initialize the analytics module.
51///
52/// Returns an `EventCollector` that can be cloned and used across threads
53/// to record connection events.
54///
55/// # Errors
56///
57/// Returns an error if ClickHouse configuration is missing or connection fails.
58pub async fn init(config: AnalyticsConfig) -> Result<EventCollector, AnalyticsError> {
59    if !config.enabled {
60        return Err(AnalyticsError::Disabled);
61    }
62
63    let clickhouse_config = config.clickhouse.as_ref().ok_or(AnalyticsError::Config(
64        "clickhouse config is required".into(),
65    ))?;
66
67    // Create bounded channel for events
68    let buffer_size = config.buffer.size;
69    let (tx, rx) = mpsc::channel(buffer_size);
70
71    // Create ClickHouse client
72    let client = writer::clickhouse::create_client(clickhouse_config)?;
73
74    // Start background writer task
75    let writer_config = config.clone();
76    tokio::spawn(async move {
77        writer::run_writer(rx, client, writer_config).await;
78    });
79
80    info!(
81        buffer_size = buffer_size,
82        batch_size = config.buffer.batch_size,
83        flush_interval_secs = config.buffer.flush_interval_secs,
84        "analytics initialized"
85    );
86
87    Ok(EventCollector::new(tx, Arc::new(config)))
88}