@@ -10,10 +10,10 @@ use bollard::{
1010 Docker ,
1111 models:: ContainerMemoryStats ,
1212 query_parameters,
13- secret:: { ContainerCpuStats , ContainerCpuUsage , ContainerStatsResponse } ,
13+ secret:: { ContainerCpuStats , ContainerCpuUsage } ,
1414} ;
1515use chrono:: DateTime ;
16- use futures_util:: stream:: TryStreamExt ;
16+ use futures_util:: stream:: StreamExt ;
1717use itertools:: Itertools ;
1818use tokio:: {
1919 fs:: OpenOptions ,
@@ -1595,36 +1595,37 @@ impl DockerStats {
15951595 let path = path. to_string ( ) ;
15961596
15971597 tokio:: spawn ( async move {
1598+ // Setup to stream statistics from Docker (default: every 1 second).
15981599 let query_parameters = query_parameters:: StatsOptionsBuilder :: new ( )
15991600 . stream ( true )
16001601 . build ( ) ;
1601- let stream = & mut docker. stats ( & name, Some ( query_parameters) ) ;
1602-
1603- // Collect the stats. This will await until the container is stopped then dump
1604- // all the stats to a log.
1605- match stream . try_collect :: < Vec < ContainerStatsResponse > > ( ) . await {
1606- Ok ( responses ) => {
1607- match OpenOptions :: new ( )
1608- . write ( true )
1609- . create ( true )
1610- . truncate ( true )
1611- . open ( format ! ( "{}/{}_stats.log" , path , name ) )
1612- . await
1613- {
1614- Ok ( mut file ) => {
1615- let _ = file
1616- . write_all ( b"Timestamp \t CPU \t MEM \t TX_Bitrate \t RX_Bitrate \n " )
1617- . await ;
1618-
1619- let mut prev_timestamp = 0i64 ;
1620-
1621- let mut prev_tx_bytes = 0u64 ;
1622- let mut prev_rx_bytes = 0u64 ;
1623-
1624- let mut prev_total_cpu_usage = 0u64 ;
1625- let mut prev_system_cpu_usage = 0u64 ;
1626-
1627- for response in responses {
1602+ let mut stream = docker. stats ( & name, Some ( query_parameters) ) ;
1603+
1604+ // Collect the stats. Open a file and write the values as they arrive.
1605+ match OpenOptions :: new ( )
1606+ . write ( true )
1607+ . create ( true )
1608+ . truncate ( true )
1609+ . open ( format ! ( "{}/{}_stats.log" , path , name ) )
1610+ . await
1611+ {
1612+ Ok ( mut file ) => {
1613+ let _ = file
1614+ . write_all ( b"Timestamp \t CPU \t MEM \t TX_Bitrate \t RX_Bitrate \n " )
1615+ . await ;
1616+
1617+ let mut prev_timestamp = 0i64 ;
1618+
1619+ let mut prev_tx_bytes = 0u64 ;
1620+ let mut prev_rx_bytes = 0u64 ;
1621+
1622+ let mut prev_total_cpu_usage = 0u64 ;
1623+ let mut prev_system_cpu_usage = 0u64 ;
1624+
1625+ // Process stats as they arrive.
1626+ while let Some ( result ) = stream . next ( ) . await {
1627+ match result {
1628+ Ok ( response) => {
16281629 match ( response. cpu_stats , response. memory_stats , response. networks )
16291630 {
16301631 (
@@ -1655,25 +1656,29 @@ impl DockerStats {
16551656 Some ( network) => {
16561657 let tx_bytes = network. tx_bytes . unwrap ( ) ;
16571658 let rx_bytes = network. rx_bytes . unwrap ( ) ;
1658- let time_delta =
1659- ( timestamp - prev_timestamp) as f32 / 1000.0 ;
1660- let tx_bitrate = ( tx_bytes - prev_tx_bytes) as f32
1661- * 8.0
1662- / time_delta;
1663- let rx_bitrate = ( rx_bytes - prev_rx_bytes) as f32
1664- * 8.0
1665- / time_delta;
1659+
1660+ let ( tx_bitrate, rx_bitrate) =
1661+ if prev_timestamp == 0 {
1662+ // Ignore the first data point since there was no reference.
1663+ ( 0.0 , 0.0 )
1664+ } else {
1665+ let time_delta =
1666+ ( timestamp - prev_timestamp) as f32
1667+ / 1000.0 ;
1668+ let tx_bitrate =
1669+ ( tx_bytes - prev_tx_bytes) as f32 * 8.0
1670+ / time_delta;
1671+ let rx_bitrate =
1672+ ( rx_bytes - prev_rx_bytes) as f32 * 8.0
1673+ / time_delta;
1674+ ( tx_bitrate, rx_bitrate)
1675+ } ;
16661676
16671677 prev_timestamp = timestamp;
16681678 prev_tx_bytes = tx_bytes;
16691679 prev_rx_bytes = rx_bytes;
16701680
1671- if prev_timestamp == 0 {
1672- // Ignore the first data point since there was no reference.
1673- ( 0.0 , 0.0 )
1674- } else {
1675- ( tx_bitrate, rx_bitrate)
1676- }
1681+ ( tx_bitrate, rx_bitrate)
16771682 }
16781683 None => {
16791684 println ! ( "Error: stat missing eth0!" ) ;
@@ -1692,8 +1697,12 @@ impl DockerStats {
16921697 // grow over time and doesn't directly reflect RingRTC's
16931698 // memory usage.
16941699 // https://docs.docker.com/engine/reference/commandline/stats/#description
1695- let memory = memory_usage
1696- - memory_stats. get ( "total_inactive_file" ) . unwrap ( ) ;
1700+ let cache_usage = * memory_stats
1701+ . get ( "total_inactive_file" )
1702+ . or_else ( || memory_stats. get ( "inactive_file" ) )
1703+ . unwrap_or ( & 0 ) ;
1704+
1705+ let memory = memory_usage. saturating_sub ( cache_usage) ;
16971706 let _ = file
16981707 . write_all (
16991708 format ! (
@@ -1717,14 +1726,15 @@ impl DockerStats {
17171726 }
17181727 }
17191728 }
1720- }
1721- Err ( err) => {
1722- println ! ( "Error creating stats file: {:?}" , err) ;
1729+ Err ( err) => {
1730+ println ! ( "Error collecting stats for {}: {:?}" , name, err) ;
1731+ break ;
1732+ }
17231733 }
17241734 }
17251735 }
17261736 Err ( err) => {
1727- println ! ( "Error collecting stats for {} : {:?}" , name , err) ;
1737+ println ! ( "Error creating stats file : {:?}" , err) ;
17281738 }
17291739 }
17301740 } ) ;
0 commit comments