1#![allow(dead_code)] use std::borrow::Cow;
4
5use vector_lib::{
6 NamedInternalEvent,
7 configurable::configurable_component,
8 counter, gauge,
9 internal_event::{
10 ComponentEventsDropped, CounterName, GaugeName, INTENTIONAL, InternalEvent, UNINTENTIONAL,
11 error_stage, error_type,
12 },
13};
14
15use crate::sinks::util::path_confinement::ConfineError;
16
17#[cfg(any(feature = "sources-file", feature = "sources-kubernetes_logs"))]
18pub use self::source::*;
19
20#[configurable_component]
22#[derive(Clone, Debug, PartialEq, Eq, Default)]
23#[serde(deny_unknown_fields)]
24pub struct FileInternalMetricsConfig {
25 #[serde(default = "crate::serde::default_false")]
30 pub include_file_tag: bool,
31}
32
33#[derive(Debug, NamedInternalEvent)]
34pub struct FileOpen {
35 pub count: usize,
36}
37
38impl InternalEvent for FileOpen {
39 fn emit(self) {
40 gauge!(GaugeName::OpenFiles).set(self.count as f64);
41 }
42}
43
44#[derive(Debug, NamedInternalEvent)]
45pub struct FileBytesSent<'a> {
46 pub byte_size: usize,
47 pub file: Cow<'a, str>,
48 pub include_file_metric_tag: bool,
49}
50
51impl InternalEvent for FileBytesSent<'_> {
52 fn emit(self) {
53 trace!(
54 message = "Bytes sent.",
55 byte_size = %self.byte_size,
56 protocol = "file",
57 file = %self.file,
58 );
59 if self.include_file_metric_tag {
60 counter!(
61 CounterName::ComponentSentBytesTotal,
62 "protocol" => "file",
63 "file" => self.file.clone().into_owned(),
64 )
65 } else {
66 counter!(
67 CounterName::ComponentSentBytesTotal,
68 "protocol" => "file",
69 )
70 }
71 .increment(self.byte_size as u64);
72 }
73}
74
75#[derive(Debug, NamedInternalEvent)]
76pub struct FileIoError<'a, P> {
77 pub error: std::io::Error,
78 pub code: &'static str,
79 pub message: &'static str,
80 pub path: &'a P,
81 pub dropped_events: usize,
82}
83
84impl<P: std::fmt::Debug> InternalEvent for FileIoError<'_, P> {
85 fn emit(self) {
86 error!(
87 message = %self.message,
88 path = ?self.path,
89 error = %self.error,
90 error_code = %self.code,
91 error_type = error_type::IO_FAILED,
92 stage = error_stage::SENDING,
93 );
94 counter!(
95 CounterName::ComponentErrorsTotal,
96 "error_code" => self.code,
97 "error_type" => error_type::IO_FAILED,
98 "stage" => error_stage::SENDING,
99 )
100 .increment(1);
101
102 if self.dropped_events > 0 {
103 emit!(ComponentEventsDropped::<UNINTENTIONAL> {
104 count: self.dropped_events,
105 reason: self.message,
106 });
107 }
108 }
109}
110
111#[derive(Debug, NamedInternalEvent)]
112pub struct FilePathOutsideBaseDirError<'a> {
113 pub path: &'a std::path::Path,
114 pub base_dir: &'a std::path::Path,
115 pub error: ConfineError,
116}
117
118impl InternalEvent for FilePathOutsideBaseDirError<'_> {
119 fn emit(self) {
120 error!(
121 message = "Rendered path is outside the configured base directory; dropping event.",
122 path = ?self.path,
123 base_dir = ?self.base_dir,
124 error = %self.error,
125 error_type = error_type::CONFINEMENT_FAILED,
126 stage = error_stage::PROCESSING,
127 );
128 counter!(
129 CounterName::ComponentErrorsTotal,
130 "error_type" => error_type::CONFINEMENT_FAILED,
131 "stage" => error_stage::PROCESSING,
132 )
133 .increment(1);
134 emit!(ComponentEventsDropped::<INTENTIONAL> {
135 count: 1,
136 reason: "Rendered path outside base_dir.",
137 });
138 }
139}
140
141#[cfg(any(feature = "sources-file", feature = "sources-kubernetes_logs"))]
142mod source {
143 use std::{io::Error, path::Path, time::Duration};
144
145 use bytes::BytesMut;
146 use vector_lib::{
147 NamedInternalEvent, counter, emit,
148 file_source_common::internal_events::FileSourceInternalEvents,
149 internal_event::{
150 ComponentEventsDropped, CounterName, INTENTIONAL, error_stage, error_type,
151 },
152 json_size::JsonSize,
153 };
154
155 use super::{FileOpen, InternalEvent};
156
157 #[derive(Debug, NamedInternalEvent)]
158 pub struct FileBytesReceived<'a> {
159 pub byte_size: usize,
160 pub file: &'a str,
161 pub include_file_metric_tag: bool,
162 }
163
164 impl InternalEvent for FileBytesReceived<'_> {
165 fn emit(self) {
166 trace!(
167 message = "Bytes received.",
168 byte_size = %self.byte_size,
169 protocol = "file",
170 file = %self.file,
171 );
172 if self.include_file_metric_tag {
173 counter!(
174 CounterName::ComponentReceivedBytesTotal,
175 "protocol" => "file",
176 "file" => self.file.to_owned()
177 )
178 } else {
179 counter!(
180 CounterName::ComponentReceivedBytesTotal,
181 "protocol" => "file",
182 )
183 }
184 .increment(self.byte_size as u64);
185 }
186 }
187
188 #[derive(Debug, NamedInternalEvent)]
189 pub struct FileEventsReceived<'a> {
190 pub count: usize,
191 pub file: &'a str,
192 pub byte_size: JsonSize,
193 pub include_file_metric_tag: bool,
194 }
195
196 impl InternalEvent for FileEventsReceived<'_> {
197 fn emit(self) {
198 trace!(
199 message = "Events received.",
200 count = %self.count,
201 byte_size = %self.byte_size,
202 file = %self.file
203 );
204 if self.include_file_metric_tag {
205 counter!(
206 CounterName::ComponentReceivedEventsTotal,
207 "file" => self.file.to_owned(),
208 )
209 .increment(self.count as u64);
210 counter!(
211 CounterName::ComponentReceivedEventBytesTotal,
212 "file" => self.file.to_owned(),
213 )
214 .increment(self.byte_size.get() as u64);
215 } else {
216 counter!(CounterName::ComponentReceivedEventsTotal).increment(self.count as u64);
217 counter!(CounterName::ComponentReceivedEventBytesTotal)
218 .increment(self.byte_size.get() as u64);
219 }
220 }
221 }
222
223 #[derive(Debug, NamedInternalEvent)]
224 pub struct FileChecksumFailed<'a> {
225 pub file: &'a Path,
226 pub include_file_metric_tag: bool,
227 }
228
229 impl InternalEvent for FileChecksumFailed<'_> {
230 fn emit(self) {
231 warn!(
232 message = "Currently ignoring file too small to fingerprint.",
233 file = %self.file.display(),
234 );
235 if self.include_file_metric_tag {
236 counter!(
237 CounterName::ChecksumErrorsTotal,
238 "file" => self.file.to_string_lossy().into_owned(),
239 )
240 } else {
241 counter!(CounterName::ChecksumErrorsTotal)
242 }
243 .increment(1);
244 }
245 }
246
247 #[derive(Debug, NamedInternalEvent)]
248 pub struct FileFingerprintReadError<'a> {
249 pub file: &'a Path,
250 pub error: Error,
251 pub include_file_metric_tag: bool,
252 }
253
254 impl InternalEvent for FileFingerprintReadError<'_> {
255 fn emit(self) {
256 error!(
257 message = "Failed reading file for fingerprinting.",
258 file = %self.file.display(),
259 error = %self.error,
260 error_code = "reading_fingerprint",
261 error_type = error_type::READER_FAILED,
262 stage = error_stage::RECEIVING,
263 );
264 if self.include_file_metric_tag {
265 counter!(
266 CounterName::ComponentErrorsTotal,
267 "error_code" => "reading_fingerprint",
268 "error_type" => error_type::READER_FAILED,
269 "stage" => error_stage::RECEIVING,
270 "file" => self.file.to_string_lossy().into_owned(),
271 )
272 } else {
273 counter!(
274 CounterName::ComponentErrorsTotal,
275 "error_code" => "reading_fingerprint",
276 "error_type" => error_type::READER_FAILED,
277 "stage" => error_stage::RECEIVING,
278 )
279 }
280 .increment(1);
281 }
282 }
283
284 const DELETION_FAILED: &str = "deletion_failed";
285
286 #[derive(Debug, NamedInternalEvent)]
287 pub struct FileDeleteError<'a> {
288 pub file: &'a Path,
289 pub error: Error,
290 pub include_file_metric_tag: bool,
291 }
292
293 impl InternalEvent for FileDeleteError<'_> {
294 fn emit(self) {
295 error!(
296 message = "Failed in deleting file.",
297 file = %self.file.display(),
298 error = %self.error,
299 error_code = DELETION_FAILED,
300 error_type = error_type::COMMAND_FAILED,
301 stage = error_stage::RECEIVING,
302 );
303 if self.include_file_metric_tag {
304 counter!(
305 CounterName::ComponentErrorsTotal,
306 "file" => self.file.to_string_lossy().into_owned(),
307 "error_code" => DELETION_FAILED,
308 "error_type" => error_type::COMMAND_FAILED,
309 "stage" => error_stage::RECEIVING,
310 )
311 } else {
312 counter!(
313 CounterName::ComponentErrorsTotal,
314 "error_code" => DELETION_FAILED,
315 "error_type" => error_type::COMMAND_FAILED,
316 "stage" => error_stage::RECEIVING,
317 )
318 }
319 .increment(1);
320 }
321 }
322
323 #[derive(Debug, NamedInternalEvent)]
324 pub struct FileDeleted<'a> {
325 pub file: &'a Path,
326 pub include_file_metric_tag: bool,
327 }
328
329 impl InternalEvent for FileDeleted<'_> {
330 fn emit(self) {
331 info!(
332 message = "File deleted.",
333 file = %self.file.display(),
334 );
335 if self.include_file_metric_tag {
336 counter!(
337 CounterName::FilesDeletedTotal,
338 "file" => self.file.to_string_lossy().into_owned(),
339 )
340 } else {
341 counter!(CounterName::FilesDeletedTotal)
342 }
343 .increment(1);
344 }
345 }
346
347 #[derive(Debug, NamedInternalEvent)]
348 pub struct FileUnwatched<'a> {
349 pub file: &'a Path,
350 pub include_file_metric_tag: bool,
351 pub reached_eof: bool,
352 }
353
354 impl InternalEvent for FileUnwatched<'_> {
355 fn emit(self) {
356 let reached_eof = if self.reached_eof { "true" } else { "false" };
357 info!(
358 message = "Stopped watching file.",
359 file = %self.file.display(),
360 reached_eof
361 );
362 if self.include_file_metric_tag {
363 counter!(
364 CounterName::FilesUnwatchedTotal,
365 "file" => self.file.to_string_lossy().into_owned(),
366 "reached_eof" => reached_eof,
367 )
368 } else {
369 counter!(
370 CounterName::FilesUnwatchedTotal,
371 "reached_eof" => reached_eof,
372 )
373 }
374 .increment(1);
375 }
376 }
377
378 #[derive(Debug, NamedInternalEvent)]
379 struct FileWatchError<'a> {
380 pub file: &'a Path,
381 pub error: Error,
382 pub include_file_metric_tag: bool,
383 }
384
385 impl InternalEvent for FileWatchError<'_> {
386 fn emit(self) {
387 error!(
388 message = "Failed to watch file.",
389 error = %self.error,
390 error_code = "watching",
391 error_type = error_type::COMMAND_FAILED,
392 stage = error_stage::RECEIVING,
393 file = %self.file.display(),
394 );
395 if self.include_file_metric_tag {
396 counter!(
397 CounterName::ComponentErrorsTotal,
398 "error_code" => "watching",
399 "error_type" => error_type::COMMAND_FAILED,
400 "stage" => error_stage::RECEIVING,
401 "file" => self.file.to_string_lossy().into_owned(),
402 )
403 } else {
404 counter!(
405 CounterName::ComponentErrorsTotal,
406 "error_code" => "watching",
407 "error_type" => error_type::COMMAND_FAILED,
408 "stage" => error_stage::RECEIVING,
409 )
410 }
411 .increment(1);
412 }
413 }
414
415 #[derive(Debug, NamedInternalEvent)]
416 pub struct FileResumed<'a> {
417 pub file: &'a Path,
418 pub file_position: u64,
419 pub include_file_metric_tag: bool,
420 }
421
422 impl InternalEvent for FileResumed<'_> {
423 fn emit(self) {
424 info!(
425 message = "Resuming to watch file.",
426 file = %self.file.display(),
427 file_position = %self.file_position
428 );
429 if self.include_file_metric_tag {
430 counter!(
431 CounterName::FilesResumedTotal,
432 "file" => self.file.to_string_lossy().into_owned(),
433 )
434 } else {
435 counter!(CounterName::FilesResumedTotal)
436 }
437 .increment(1);
438 }
439 }
440
441 #[derive(Debug, NamedInternalEvent)]
442 pub struct FileAdded<'a> {
443 pub file: &'a Path,
444 pub include_file_metric_tag: bool,
445 }
446
447 impl InternalEvent for FileAdded<'_> {
448 fn emit(self) {
449 info!(
450 message = "Found new file to watch.",
451 file = %self.file.display(),
452 );
453 if self.include_file_metric_tag {
454 counter!(
455 CounterName::FilesAddedTotal,
456 "file" => self.file.to_string_lossy().into_owned(),
457 )
458 } else {
459 counter!(CounterName::FilesAddedTotal)
460 }
461 .increment(1);
462 }
463 }
464
465 #[derive(Debug, NamedInternalEvent)]
466 pub struct FileCheckpointed {
467 pub count: usize,
468 pub duration: Duration,
469 }
470
471 impl InternalEvent for FileCheckpointed {
472 fn emit(self) {
473 debug!(
474 message = "Files checkpointed.",
475 count = %self.count,
476 duration_ms = self.duration.as_millis() as u64,
477 );
478 counter!(CounterName::CheckpointsTotal).increment(self.count as u64);
479 }
480 }
481
482 #[derive(Debug, NamedInternalEvent)]
483 pub struct FileCheckpointWriteError {
484 pub error: Error,
485 }
486
487 impl InternalEvent for FileCheckpointWriteError {
488 fn emit(self) {
489 error!(
490 message = "Failed writing checkpoints.",
491 error = %self.error,
492 error_code = "writing_checkpoints",
493 error_type = error_type::WRITER_FAILED,
494 stage = error_stage::RECEIVING,
495 );
496 counter!(
497 CounterName::ComponentErrorsTotal,
498 "error_code" => "writing_checkpoints",
499 "error_type" => error_type::WRITER_FAILED,
500 "stage" => error_stage::RECEIVING,
501 )
502 .increment(1);
503 }
504 }
505
506 #[derive(Debug, NamedInternalEvent)]
507 pub struct PathGlobbingError<'a> {
508 pub path: &'a Path,
509 pub error: &'a Error,
510 }
511
512 impl InternalEvent for PathGlobbingError<'_> {
513 fn emit(self) {
514 error!(
515 message = "Failed to glob path.",
516 error = %self.error,
517 error_code = "globbing",
518 error_type = error_type::READER_FAILED,
519 stage = error_stage::RECEIVING,
520 path = %self.path.display(),
521 );
522 counter!(
523 CounterName::ComponentErrorsTotal,
524 "error_code" => "globbing",
525 "error_type" => error_type::READER_FAILED,
526 "stage" => error_stage::RECEIVING,
527 )
528 .increment(1);
529 }
530 }
531
532 #[derive(Debug, NamedInternalEvent)]
533 pub struct FileLineTooBigError<'a> {
534 pub truncated_bytes: &'a BytesMut,
535 pub configured_limit: usize,
536 pub encountered_size_so_far: usize,
537 }
538
539 impl InternalEvent for FileLineTooBigError<'_> {
540 fn emit(self) {
541 error!(
542 message = "Found line that exceeds max_line_bytes; discarding.",
543 truncated_bytes = ?self.truncated_bytes,
544 configured_limit = self.configured_limit,
545 encountered_size_so_far = self.encountered_size_so_far,
546 error_type = error_type::CONDITION_FAILED,
547 stage = error_stage::RECEIVING,
548 );
549 counter!(
550 CounterName::ComponentErrorsTotal,
551 "error_code" => "reading_line_from_file",
552 "error_type" => error_type::CONDITION_FAILED,
553 "stage" => error_stage::RECEIVING,
554 )
555 .increment(1);
556 emit!(ComponentEventsDropped::<INTENTIONAL> {
557 count: 1,
558 reason: "Found line that exceeds max_line_bytes; discarding.",
559 });
560 }
561 }
562
563 #[derive(Clone)]
564 pub struct FileSourceInternalEventsEmitter {
565 pub include_file_metric_tag: bool,
566 }
567
568 impl FileSourceInternalEvents for FileSourceInternalEventsEmitter {
569 fn emit_file_added(&self, file: &Path) {
570 emit!(FileAdded {
571 file,
572 include_file_metric_tag: self.include_file_metric_tag
573 });
574 }
575
576 fn emit_file_resumed(&self, file: &Path, file_position: u64) {
577 emit!(FileResumed {
578 file,
579 file_position,
580 include_file_metric_tag: self.include_file_metric_tag
581 });
582 }
583
584 fn emit_file_watch_error(&self, file: &Path, error: Error) {
585 emit!(FileWatchError {
586 file,
587 error,
588 include_file_metric_tag: self.include_file_metric_tag
589 });
590 }
591
592 fn emit_file_unwatched(&self, file: &Path, reached_eof: bool) {
593 emit!(FileUnwatched {
594 file,
595 include_file_metric_tag: self.include_file_metric_tag,
596 reached_eof
597 });
598 }
599
600 fn emit_file_deleted(&self, file: &Path) {
601 emit!(FileDeleted {
602 file,
603 include_file_metric_tag: self.include_file_metric_tag
604 });
605 }
606
607 fn emit_file_delete_error(&self, file: &Path, error: Error) {
608 emit!(FileDeleteError {
609 file,
610 error,
611 include_file_metric_tag: self.include_file_metric_tag
612 });
613 }
614
615 fn emit_file_fingerprint_read_error(&self, file: &Path, error: Error) {
616 emit!(FileFingerprintReadError {
617 file,
618 error,
619 include_file_metric_tag: self.include_file_metric_tag
620 });
621 }
622
623 fn emit_file_checksum_failed(&self, file: &Path) {
624 emit!(FileChecksumFailed {
625 file,
626 include_file_metric_tag: self.include_file_metric_tag
627 });
628 }
629
630 fn emit_file_checkpointed(&self, count: usize, duration: Duration) {
631 emit!(FileCheckpointed { count, duration });
632 }
633
634 fn emit_file_checkpoint_write_error(&self, error: Error) {
635 emit!(FileCheckpointWriteError { error });
636 }
637
638 fn emit_files_open(&self, count: usize) {
639 emit!(FileOpen { count });
640 }
641
642 fn emit_path_globbing_failed(&self, path: &Path, error: &Error) {
643 emit!(PathGlobbingError { path, error });
644 }
645
646 fn emit_file_line_too_long(
647 &self,
648 truncated_bytes: &bytes::BytesMut,
649 configured_limit: usize,
650 encountered_size_so_far: usize,
651 ) {
652 emit!(FileLineTooBigError {
653 truncated_bytes,
654 configured_limit,
655 encountered_size_so_far
656 });
657 }
658 }
659}