Repository: DataDog/dd-agent

Issue:
add system.mem.pct_used metric 
Record % of memory used as a metric for easy alerts.

Open question: should it include free + cached or just free?



Discussion:
Any decision on whether pct_used should include cached and buffered memory or not? Also, to what precision do we want to have these values? Do we want pct_used for both physical memory and swap?


Resolving patch:
diff --git a/checks/collector.py b/checks/collector.py
--- a/checks/collector.py
+++ b/checks/collector.py
@@ -167,11 +167,13 @@ def run(self, checksd=None):
             if memory:
                 payload.update({
                     'memPhysUsed' : memory.get('physUsed'), 
+                    'memPhysPctUsable' : memory.get('physPctUsable'), 
                     'memPhysFree' : memory.get('physFree'), 
                     'memPhysTotal' : memory.get('physTotal'), 
                     'memPhysUsable' : memory.get('physUsable'), 
                     'memSwapUsed' : memory.get('swapUsed'), 
                     'memSwapFree' : memory.get('swapFree'), 
+                    'memSwapPctFree' : memory.get('swapPctFree'), 
                     'memSwapTotal' : memory.get('swapTotal'), 
                     'memCached' : memory.get('physCached'), 
                     'memBuffers': memory.get('physBuffers'),
diff --git a/checks/system/unix.py b/checks/system/unix.py
--- a/checks/system/unix.py
+++ b/checks/system/unix.py
@@ -405,6 +405,8 @@ def check(self, agentConfig):
                 memData['physUsed'] = memData['physTotal'] - memData['physFree']
                 # Usable is relative since cached and buffers are actually used to speed things up.
                 memData['physUsable'] = memData['physFree'] + memData['physBuffers'] + memData['physCached']
+                # Make PctUsable an integer value for precision
+                memData['physPctUsable'] = float(memData['physUsable']) / float(memData['physTotal'])
             except:
                 self.logger.exception('Cannot compute stats from /proc/meminfo')
             
@@ -415,6 +417,8 @@ def check(self, agentConfig):
                 memData['swapFree']  = int(meminfo.get('SwapFree', 0)) / 1024
 
                 memData['swapUsed'] =  memData['swapTotal'] - memData['swapFree']
+                # Make PctFree an integer value for precision
+                memData['swapPctFree'] = float(memData['swapFree']) / float(memData['swapTotal'])
             except:
                 self.logger.exception('Cannot compute swap stats')
             
@@ -487,6 +491,8 @@ def check(self, agentConfig):
                                           int(meminfo.get('v_cache_count', 0)) +
                                           int(meminfo.get('v_inactive_count', 0))) *
                                          pageSize) / 1048576
+                # Make PctUsable an integer value for precision
+                memData['physPctUsable'] = float(memData['physUsable']) / float(memData['physTotal'])
             except:
                 self.logger.exception('Cannot compute stats from /proc/meminfo')
             
@@ -528,6 +534,8 @@ def check(self, agentConfig):
                 memData["swapTotal"] = convert(entries["swapcap"])
                 memData["swapUsed"]  = convert(entries["swap"])
                 memData["swapFree"]  = memData["swapTotal"] - memData["swapUsed"]
+                # Make PctFree an integer value for precision
+                memData['swapPctFree'] = float(memData['swapFree']) / float(memData['swapTotal'])
                 return memData
             except:
                 self.logger.exception("Cannot compute mem stats from kstat -c zone_memory_cap")


Test patch:
diff --git a/tests/test_system.py b/tests/test_system.py
--- a/tests/test_system.py
+++ b/tests/test_system.py
@@ -130,7 +130,7 @@ def testMemory(self):
         global logger
         res = Memory(logger).check({})
         if sys.platform == 'linux2':
-            for k in ("swapTotal", "swapFree", "swapUsed", "physTotal", "physFree", "physUsed", "physBuffers", "physCached", "physUsable", "physShared"):
+            for k in ("swapTotal", "swapFree", "swapPctFree", "swapUsed", "physTotal", "physFree", "physUsed", "physBuffers", "physCached", "physUsable", "physPctUsable", "physShared"):
                 assert k in res, res
             assert res["swapTotal"] == res["swapFree"] + res["swapUsed"]
             assert res["physTotal"] == res["physFree"] + res["physUsed"]