1
- use std:: { collections:: VecDeque , io, path:: Path , sync:: atomic:: Ordering } ;
1
+ mod cgroup;
2
+
3
+ use std:: { collections:: VecDeque , io, sync:: atomic:: Ordering } ;
2
4
3
- use cgroups_rs:: cgroup:: Cgroup ;
4
5
use metrics:: gauge;
5
6
use nix:: errno:: Errno ;
6
7
use procfs:: ProcError :: PermissionDenied ;
@@ -9,6 +10,7 @@ use rustc_hash::{FxHashMap, FxHashSet};
9
10
use tracing:: { error, warn} ;
10
11
11
12
use crate :: observer:: memory:: { Regions , Rollup } ;
13
+ use cgroup:: v2;
12
14
13
15
use super :: RSS_BYTES ;
14
16
@@ -27,8 +29,8 @@ pub enum Error {
27
29
/// Wrapper for [`procfs::ProcError`]
28
30
#[ error( "Unable to read procfs: {0}" ) ]
29
31
Proc ( #[ from] procfs:: ProcError ) ,
30
- #[ error( "Unable to read cgroups : {0}" ) ]
31
- CGroups ( #[ from] cgroups_rs :: error :: Error ) ,
32
+ #[ error( "Unable to read cgroup : {0}" ) ]
33
+ CGroup ( #[ from] v2 :: Error ) ,
32
34
}
33
35
34
36
macro_rules! report_status_field {
@@ -401,96 +403,8 @@ impl Sampler {
401
403
// if possible we compute the working set of the cgroup
402
404
// using the same heuristic as kubernetes:
403
405
// total_usage - inactive_file
404
- let cgroup = get_cgroup ( pid as _ ) ?;
405
- if let Some ( memory_controller) =
406
- cgroup. controller_of :: < cgroups_rs:: memory:: MemController > ( )
407
- {
408
- let mem_stat = memory_controller. memory_stat ( ) ;
409
-
410
- let inactive_file = if cgroup. v2 ( ) {
411
- mem_stat. stat . inactive_file
412
- } else {
413
- mem_stat. stat . total_inactive_file
414
- } ;
415
- let usage = mem_stat. usage_in_bytes ;
416
- let working_set = if usage < inactive_file {
417
- 0
418
- } else {
419
- usage - inactive_file
420
- } ;
421
-
422
- gauge ! ( "working_set_bytes" ) . set ( working_set as f64 ) ;
423
- gauge ! ( "memory.working_set_bytes" ) . set ( working_set as f64 ) ;
424
-
425
- gauge ! ( "memory.fail_cnt" ) . set ( mem_stat. fail_cnt as f64 ) ;
426
- gauge ! ( "memory.limit_bytes" ) . set ( mem_stat. limit_in_bytes as f64 ) ;
427
- gauge ! ( "memory.usage_in_bytes" ) . set ( mem_stat. usage_in_bytes as f64 ) ;
428
- gauge ! ( "memory.max_usage_in_bytes" ) . set ( mem_stat. max_usage_in_bytes as f64 ) ;
429
- gauge ! ( "memory.soft_limit_in_bytes" ) . set ( mem_stat. soft_limit_in_bytes as f64 ) ;
430
-
431
- gauge ! ( "memory.stat.cache" ) . set ( mem_stat. stat . cache as f64 ) ;
432
- gauge ! ( "memory.stat.rss" ) . set ( mem_stat. stat . rss as f64 ) ;
433
- gauge ! ( "memory.stat.rss_huge" ) . set ( mem_stat. stat . rss_huge as f64 ) ;
434
- gauge ! ( "memory.stat.shmem" ) . set ( mem_stat. stat . shmem as f64 ) ;
435
- gauge ! ( "memory.stat.mapped_file" ) . set ( mem_stat. stat . mapped_file as f64 ) ;
436
- gauge ! ( "memory.stat.dirty" ) . set ( mem_stat. stat . dirty as f64 ) ;
437
- gauge ! ( "memory.stat.writeback" ) . set ( mem_stat. stat . writeback as f64 ) ;
438
- gauge ! ( "memory.stat.swap" ) . set ( mem_stat. stat . swap as f64 ) ;
439
- gauge ! ( "memory.stat.pgpgin" ) . set ( mem_stat. stat . pgpgin as f64 ) ;
440
- gauge ! ( "memory.stat.pgpgout" ) . set ( mem_stat. stat . pgpgout as f64 ) ;
441
- gauge ! ( "memory.stat.pgfault" ) . set ( mem_stat. stat . pgfault as f64 ) ;
442
- gauge ! ( "memory.stat.pgmajfault" ) . set ( mem_stat. stat . pgmajfault as f64 ) ;
443
- gauge ! ( "memory.stat.inactive_anon" ) . set ( mem_stat. stat . inactive_anon as f64 ) ;
444
- gauge ! ( "memory.stat.active_anon" ) . set ( mem_stat. stat . active_anon as f64 ) ;
445
- gauge ! ( "memory.stat.inactive_file" ) . set ( mem_stat. stat . inactive_file as f64 ) ;
446
- gauge ! ( "memory.stat.active_file" ) . set ( mem_stat. stat . active_file as f64 ) ;
447
- gauge ! ( "memory.stat.unevictable" ) . set ( mem_stat. stat . unevictable as f64 ) ;
448
- gauge ! ( "memory.stat.hierarchical_memory_limit" )
449
- . set ( mem_stat. stat . hierarchical_memory_limit as f64 ) ;
450
- gauge ! ( "memory.stat.hierarchical_memsw_limit" )
451
- . set ( mem_stat. stat . hierarchical_memsw_limit as f64 ) ;
452
- gauge ! ( "memory.stat.total_cache" ) . set ( mem_stat. stat . total_cache as f64 ) ;
453
- gauge ! ( "memory.stat.total_rss" ) . set ( mem_stat. stat . total_rss as f64 ) ;
454
- gauge ! ( "memory.stat.total_rss_huge" ) . set ( mem_stat. stat . total_rss_huge as f64 ) ;
455
- gauge ! ( "memory.stat.total_shmem" ) . set ( mem_stat. stat . total_shmem as f64 ) ;
456
- gauge ! ( "memory.stat.total_mapped_file" ) . set ( mem_stat. stat . total_mapped_file as f64 ) ;
457
- gauge ! ( "memory.stat.total_dirty" ) . set ( mem_stat. stat . total_dirty as f64 ) ;
458
- gauge ! ( "memory.stat.total_writeback" ) . set ( mem_stat. stat . total_writeback as f64 ) ;
459
- gauge ! ( "memory.stat.total_swap" ) . set ( mem_stat. stat . total_swap as f64 ) ;
460
- gauge ! ( "memory.stat.total_pgpgin" ) . set ( mem_stat. stat . total_pgpgin as f64 ) ;
461
- gauge ! ( "memory.stat.total_pgpgout" ) . set ( mem_stat. stat . total_pgpgout as f64 ) ;
462
- gauge ! ( "memory.stat.total_pgfault" ) . set ( mem_stat. stat . total_pgfault as f64 ) ;
463
- gauge ! ( "memory.stat.total_pgmajfault" ) . set ( mem_stat. stat . total_pgmajfault as f64 ) ;
464
- gauge ! ( "memory.stat.total_inactive_anon" )
465
- . set ( mem_stat. stat . total_inactive_anon as f64 ) ;
466
- gauge ! ( "memory.stat.total_active_anon" ) . set ( mem_stat. stat . total_active_anon as f64 ) ;
467
- gauge ! ( "memory.stat.total_inactive_file" )
468
- . set ( mem_stat. stat . total_inactive_file as f64 ) ;
469
- gauge ! ( "memory.stat.total_active_file" ) . set ( mem_stat. stat . total_active_file as f64 ) ;
470
- gauge ! ( "memory.stat.total_unevictable" ) . set ( mem_stat. stat . total_unevictable as f64 ) ;
471
- }
472
- // Load the CPU controller and get the cpu.stat String out of the
473
- // cgroup, parse whatever fields are present and report them back
474
- // out as metrics.
475
- if let Some ( cpu_controller) = cgroup. controller_of :: < cgroups_rs:: cpu:: CpuController > ( ) {
476
- let cpu = cpu_controller. cpu ( ) ;
477
- for line in cpu. stat . lines ( ) {
478
- let mut fields = line. split_whitespace ( ) ;
479
- let metric_name = fields. next ( ) . unwrap_or_default ( ) ;
480
- let value = fields. next ( ) . unwrap_or_default ( ) ;
481
- gauge ! ( format!( "cpu.{metric_name}" ) )
482
- . set ( value. parse :: < f64 > ( ) . unwrap_or_default ( ) ) ;
483
- }
484
- if let Ok ( shares) = cpu_controller. shares ( ) {
485
- gauge ! ( "cpu.shares" ) . set ( shares as f64 ) ;
486
- }
487
- if let Ok ( cfs_period) = cpu_controller. cfs_period ( ) {
488
- gauge ! ( "cpu.cfs_period" ) . set ( cfs_period as f64 ) ;
489
- }
490
- if let Ok ( cfs_quota) = cpu_controller. cfs_quota ( ) {
491
- gauge ! ( "cpu.cfs_quota" ) . set ( cfs_quota as f64 ) ;
492
- }
493
- }
406
+ let cgroup_path = v2:: get_path ( pid) . await ?;
407
+ v2:: poll ( cgroup_path) . await ?;
494
408
}
495
409
496
410
gauge ! ( "num_processes" ) . set ( total_processes as f64 ) ;
@@ -608,38 +522,3 @@ fn percentage(delta_ticks: f64, delta_time: f64, num_cores: f64) -> f64 {
608
522
609
523
overall_percentage. clamp ( 0.0 , 100.0 * num_cores)
610
524
}
611
-
612
- #[ inline]
613
- fn get_cgroup ( pid : u32 ) -> Result < Cgroup , Error > {
614
- let hierarchies = cgroups_rs:: hierarchies:: auto ( ) ;
615
- if hierarchies. v2 ( ) {
616
- // for cgroups v2, we parse `/proc/<pid>/cgroup` looking for the main cgroup
617
- // relative path. We then use this to load the correct cgroup.
618
- // For unknown reasons, the cgroups_rs lib is not able to do this on its own.
619
- // Heavily inspired by
620
- // https://github.com/containerd/rust-extensions/blob/3d4de340d83aa06dff24fbf73d7d584ebe77c7ec/crates/shim/src/cgroup.rs#L178
621
-
622
- let eof = || io:: Error :: from ( io:: ErrorKind :: UnexpectedEof ) ;
623
- let path = format ! ( "/proc/{pid}/cgroup" ) ;
624
- let content = std:: fs:: read_to_string ( path) ?;
625
-
626
- let first_line = content. lines ( ) . next ( ) . ok_or_else ( eof) ?;
627
- let ( _, path_part) = first_line. split_once ( "::" ) . ok_or_else ( eof) ?;
628
-
629
- let mut path_parts = path_part. split ( '/' ) . skip ( 1 ) ;
630
- let namespace = path_parts. next ( ) . ok_or_else ( eof) ?;
631
- let cgroup_name = path_parts. next ( ) . ok_or_else ( eof) ?;
632
-
633
- Ok ( Cgroup :: load (
634
- hierarchies,
635
- format ! ( "/sys/fs/cgroup/{namespace}/{cgroup_name}" ) . as_str ( ) ,
636
- ) )
637
- } else {
638
- let relative_paths = cgroups_rs:: cgroup:: get_cgroups_relative_paths_by_pid ( pid) ?;
639
- Ok ( Cgroup :: load_with_relative_paths (
640
- hierarchies,
641
- Path :: new ( "." ) ,
642
- relative_paths,
643
- ) )
644
- }
645
- }
0 commit comments