1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
//! A [`tracing-subscriber`](https://github.com/tokio-rs/tracing) layer for sending logs to [Better Stack](https://betterstack.com).
//!
//! This crate provides a seamless integration between Rust's `tracing` ecosystem and Better Stack's
//! log management platform. It automatically collects, batches, and sends your application logs
//! to Better Stack for centralized logging, monitoring, and analysis.
//!
//! # Features
//!
//! - **🚀 Asynchronous & Non-blocking**: Logs are sent in background tasks without blocking your application
//! - **📦 Automatic Batching**: Efficiently batches logs to minimize HTTP requests and improve performance
//! - **🔄 Retry Logic**: Built-in exponential backoff retry mechanism for handling transient failures
//! - **🎯 Structured Logging**: Full support for structured fields, span context, and nested spans
//! - **⚡ Lazy Initialization**: Gracefully handles tokio runtime initialization and shutdown
//! - **🛡️ Production Ready**: Comprehensive error handling with fail-open behavior to never crash your app
//! - **🗜️ Multiple Formats**: Choose between JSON and MessagePack serialization formats
//!
//! # Quick Start
//!
//! ```no_run
//! use tracing::{info, error};
//! use tracing_better_stack::{BetterStackLayer, BetterStackConfig};
//! use tracing_subscriber::prelude::*;
//!
//! #[tokio::main]
//! async fn main() {
//! // Configure Better Stack layer with your ingesting host and source token
//! // Get these from https://logs.betterstack.com/
//! let layer = BetterStackLayer::new(
//! BetterStackConfig::builder(
//! "s1234567.us-east-9.betterstackdata.com",
//! "your-source-token"
//! ).build()
//! );
//!
//! // Initialize tracing with the Better Stack layer
//! tracing_subscriber::registry()
//! .with(layer)
//! .init();
//!
//! // Your logs are now being sent to Better Stack!
//! info!(user_id = 123, "User logged in");
//! error!(error = "Connection timeout", "Failed to connect to database");
//! }
//! ```
//!
//! # Serialization Formats
//!
//! Better Stack supports both JSON and MessagePack formats. This crate provides both via
//! mutually exclusive feature flags:
//!
//! ## MessagePack (Default)
//!
//! MessagePack is a binary serialization format that's more compact and efficient than JSON:
//!
//! ```toml
//! [dependencies]
//! tracing-better-stack = "0.1" # Uses MessagePack by default
//! ```
//!
//! ## JSON
//!
//! JSON is human-readable and useful for debugging:
//!
//! ```toml
//! [dependencies]
//! tracing-better-stack = { version = "0.1", default-features = false, features = ["json"] }
//! ```
//!
//! # Configuration
//!
//! The [`BetterStackConfig`] builder provides extensive configuration options:
//!
//! ```no_run
//! use std::time::Duration;
//! use tracing_better_stack::{BetterStackLayer, BetterStackConfig};
//!
//! let layer = BetterStackLayer::new(
//! BetterStackConfig::builder(
//! "s1234567.us-east-9.betterstackdata.com",
//! "your-source-token"
//! )
//! .batch_size(200) // Max events per batch
//! .batch_timeout(Duration::from_secs(10)) // Max time between batches
//! .max_retries(5) // Retry attempts on failure
//! .initial_retry_delay(Duration::from_millis(200)) // Initial backoff delay
//! .max_retry_delay(Duration::from_secs(30)) // Maximum backoff delay
//! .include_location(true) // Include file/line info
//! .include_spans(true) // Include span context
//! .build()
//! );
//! ```
//!
//! # Structured Logging
//!
//! Take full advantage of tracing's structured logging capabilities:
//!
//! ```
//! use tracing::{info, instrument, warn};
//!
//! #[instrument(fields(request_id = %request_id))]
//! fn process_order(order_id: u64, request_id: &str) {
//! info!(
//! order_id,
//! status = "processing",
//! amount = 99.99,
//! currency = "USD",
//! "Processing payment for order"
//! );
//!
//! // Nested spans are automatically included
//! process_payment(order_id);
//! }
//!
//! #[instrument]
//! fn process_payment(order_id: u64) {
//! warn!(order_id, "Payment gateway slow");
//! }
//! ```
//!
//! # Integration with Other Layers
//!
//! Combine with other tracing layers for comprehensive observability:
//!
//! ```no_run
//! use tracing_subscriber::prelude::*;
//! use tracing_subscriber::{fmt, EnvFilter};
//! use tracing_better_stack::{BetterStackLayer, BetterStackConfig};
//!
//! tracing_subscriber::registry()
//! // Better Stack for production logging
//! .with(BetterStackLayer::new(
//! BetterStackConfig::builder("host", "token").build()
//! ))
//! // Console output for local development
//! .with(fmt::layer().pretty())
//! // Environment-based filtering
//! .with(EnvFilter::from_default_env())
//! .init();
//! ```
//!
//! # How It Works
//!
//! 1. **Event Collection**: The layer intercepts tracing events and converts them to log events
//! 2. **Batching**: Events are collected into batches (configurable size and timeout)
//! 3. **Serialization**: Batches are serialized to MessagePack or JSON
//! 4. **Async Sending**: Batches are sent asynchronously to Better Stack's HTTP API
//! 5. **Retry Logic**: Failed requests are retried with exponential backoff
//! 6. **Graceful Degradation**: Errors are logged but never panic or block your application
//!
//! # Performance Considerations
//!
//! - **Batching**: Reduces network overhead by sending multiple logs in a single request
//! - **Async Processing**: All network I/O happens in background tasks
//! - **MessagePack**: ~30-50% more compact than JSON, reducing bandwidth usage
//! - **Bounded Buffers**: Memory usage is controlled via batch size limits
//! - **Fail-Open**: If Better Stack is unreachable, logs are dropped without affecting your app
//!
//! # Error Handling
//!
//! This crate is designed to never panic or interfere with your application:
//!
//! - Network errors are logged to stderr and retried
//! - Serialization errors are logged and the batch is dropped
//! - Full batches trigger an immediate send
//! - The layer continues working even if Better Stack is down
// Compile-time check to ensure only one serialization format is enabled
compile_error!;
compile_error!;
pub use ;
pub use ;
pub use BetterStackLayer;