file_collector/
file_collector.rs1use data_hook::{data_hook, set_collector, Collect, Record};
7use std::collections::HashMap;
8use std::fs::{File, OpenOptions};
9use std::io::{BufWriter, Write};
10use std::path::{Path, PathBuf};
11use std::sync::Mutex;
12use std::thread;
13use std::time::Duration;
14
15pub struct FileCollector {
17 output_dir: PathBuf,
18 writers: Mutex<HashMap<String, BufWriter<File>>>,
19}
20
21impl FileCollector {
22 pub fn new<P: AsRef<Path>>(output_dir: P) -> std::io::Result<Self> {
24 let output_dir = output_dir.as_ref().to_path_buf();
25
26 if !output_dir.exists() {
28 std::fs::create_dir_all(&output_dir)?;
29 }
30
31 Ok(Self {
32 output_dir,
33 writers: Mutex::new(HashMap::new()),
34 })
35 }
36
37 fn get_or_create_writer(&self, category: &str) -> std::io::Result<()> {
39 let mut writers = self.writers.lock().unwrap();
40
41 if !writers.contains_key(category) {
42 let file_path = self.output_dir.join(format!("{}.jsonl", category));
43 let file = OpenOptions::new()
44 .create(true)
45 .append(true)
46 .open(file_path)?;
47 let writer = BufWriter::new(file);
48 writers.insert(category.to_string(), writer);
49 }
50
51 Ok(())
52 }
53}
54
55impl Collect for FileCollector {
56 fn collect(&self, record: &Record) {
57 if let Err(e) = self.get_or_create_writer(&record.category) {
58 eprintln!("Failed to create writer for category {}: {}", record.category, e);
59 return;
60 }
61
62 let mut writers = self.writers.lock().unwrap();
63 if let Some(writer) = writers.get_mut(&record.category) {
64 let json_line = format!(
66 r#"{{"category":"{}","data":"{}"}}"#,
67 record.category,
68 record.data.replace('"', r#"\""#).replace('\n', r#"\n"#)
69 );
70
71 if let Err(e) = writeln!(writer, "{}", json_line) {
72 eprintln!("Failed to write data record: {}", e);
73 }
74 }
75 }
76
77 fn flush(&self) {
78 let mut writers = self.writers.lock().unwrap();
79 for writer in writers.values_mut() {
80 let _ = writer.flush();
81 }
82 }
83}
84
85impl Drop for FileCollector {
86 fn drop(&mut self) {
87 self.flush();
88 }
89}
90
91fn main() -> Result<(), Box<dyn std::error::Error>> {
92 println!("Data Hook Example with File Collector");
93 println!("=====================================");
94
95 let collector = FileCollector::new("data_output")?;
97 let collector: &'static FileCollector = Box::leak(Box::new(collector));
98 set_collector(collector);
99
100 println!("Initialized file collector. Data will be saved to 'data_output' directory.");
101
102 simulate_user_actions();
104 simulate_performance_metrics();
105 simulate_error_events();
106
107 collector.flush();
109
110 println!("\nExample completed! Check the 'data_output' directory for collected data files:");
111 println!("- user_action.jsonl - User interaction events");
112 println!("- performance.jsonl - Performance metrics");
113 println!("- error.jsonl - Error events");
114
115 Ok(())
116}
117
118fn simulate_user_actions() {
119 println!("\n--- Simulating User Actions ---");
120
121 data_hook!("user_action", "User opened application");
123
124 let user_id = 12345;
126 data_hook!("user_action", "User {} logged in", user_id);
127
128 for i in 1..=3 {
130 data_hook!("user_action", "User clicked button: submit_{}", i);
131 thread::sleep(Duration::from_millis(100));
132 }
133
134 data_hook!("user_action", "User navigated to page: {}", "/dashboard");
136 data_hook!("user_action", "User navigated to page: {}", "/profile");
137
138 println!("Collected {} user action events", 6);
139}
140
141fn simulate_performance_metrics() {
142 println!("\n--- Simulating Performance Metrics ---");
143
144 let response_times = [45, 123, 67, 234, 89];
146 for (i, time) in response_times.iter().enumerate() {
147 data_hook!("performance", "API request {} took {} ms", i + 1, time);
148 thread::sleep(Duration::from_millis(50));
149 }
150
151 data_hook!("performance", "Memory usage: {} MB", 256);
153 data_hook!("performance", "CPU usage: {}%", 15.7);
154
155 data_hook!("performance", "Database query executed in {} ms: {}", 89, "SELECT * FROM users");
157
158 println!("Collected {} performance metrics", 8);
159}
160
161fn simulate_error_events() {
162 println!("\n--- Simulating Error Events ---");
163
164 data_hook!("error", "Network timeout: Failed to connect to {}", "api.example.com");
166
167 data_hook!("error", "Validation failed: {} field is required", "email");
169
170 data_hook!("error", "File not found: {}", "/path/to/config.json");
172
173 let error_code = 500;
175 let error_msg = "Internal server error";
176 data_hook!("error", "HTTP {} - {}: Request failed for endpoint /api/users", error_code, error_msg);
177
178 println!("Collected {} error events", 4);
179}
180
181mod user_service {
183 use data_hook::data_hook;
184
185 pub fn create_user(username: &str) {
186 data_hook!("user_action", "Creating user: {}", username);
188
189 std::thread::sleep(std::time::Duration::from_millis(10));
191
192 data_hook!("user_action", "User created successfully: {}", username);
193 }
194
195 pub fn delete_user(user_id: u32) {
196 data_hook!("user_action", "Deleting user with ID: {}", user_id);
197
198 std::thread::sleep(std::time::Duration::from_millis(5));
200
201 data_hook!("user_action", "User {} deleted", user_id);
202 }
203}