Hi,
On 2016-07-08 20:29, Marko Myllynen wrote:
> On 2016-07-08 18:24, Frank Ch. Eigler wrote:
>>> [...]
>>> I think I've sorted out the above but I've got one related question, is
>>> this still expected based on your explanation above or something else?
>>
>> Yes, I think it's the same thing.
>>
>>> So pmval(1) describes units as "millisec (converting to time
>>> utilization)" [...] Is the only confusion on this end or is pmval(1)
>>> perhaps a bit misleading here?
>>
>> The key is that pmval's "time utilization" parenthetical overrides the
>> previous "milliseconds" scale and replaces it with an implicit
>> "sec/sec" one.
I noticed that pmdumptext(1) does the same thing after all - when in
its "interactive mode."
But given that pmrep(1) already supports specifying unit/scale even on
per-metric basis, we don't have to hard-code this but we can give the
choice to the user. For instance, with kernel.all.cpu.user by default
show the unscaled ms/s value but by defining time-scale with -y the
user gets the time utilization (s/s) if s/he so wishes. I adjusted
the man page for this, please do reword if you can think how to state
this more clearly there.
Below is now finally a patch which I don't plan to update at this
stage any more unless there's some feedback (IOW, I think it's ready
for merging). The 1071 output still differs mysteriously, I can't
explain why pmfg finds "extra" values, and only for some metrics (I'd
have expected it to find them for none or all given the pmdumplog -a
output for the archive in question). But since we're getting more
data than before, perhaps that's just a good thing.
There might still be room for some minor internal cleanups in few
places but I think it's best to do this kind of migration somewhat
conservatively.
---
qa/1069.out | 100 ++++++++++----------
qa/1071.out | 12 ++-
src/pmrep/pmrep.1 | 16 +++-
src/pmrep/pmrep.conf | 7 +-
src/pmrep/pmrep.py | 251 +++++++++++++++------------------------------------
5 files changed, 150 insertions(+), 236 deletions(-)
diff --git a/qa/1069.out b/qa/1069.out
index 2c330b3..2243722 100644
--- a/qa/1069.out
+++ b/qa/1069.out
@@ -19,28 +19,28 @@ HH:MM:SS 1
== basic archive mode reporting
s.seconds s.milliseconds
- util util
+ s/s ms/s
20:36:45 N/A N/A
20:36:47 N/A N/A
-20:36:49 1.00 1.00
-20:36:51 1.00 1.00
-20:36:53 1.00 1.00
+20:36:49 1.00 1000.03
+20:36:51 1.00 1000.00
+20:36:53 1.00 1000.02
== basic configuration file handling
s.seconds s.milliseconds
- util util
+ s/s ms/s
N/A N/A
N/A N/A
- 1.000 1.000
- 1.000 1.000
- 1.000 1.000
+ 1.000 1000.033
+ 1.000 1000.001
+ 1.000 1000.016
== exercise various output options
s.seconds s.milliseconds
- util util
+ s/s ms/s
20:36:45 N/A N/A
20:36:47 N/A N/A
-20:36:49 1.000 1.000
-20:36:51 1.000 1.000
-20:36:53 1.000 1.000
+20:36:49 1.000 1000.033
+20:36:51 1.000 1000.001
+20:36:53 1.000 1000.016
---
archive: QAPATH/archives/sample-secs
@@ -54,7 +54,7 @@ HH:MM:SS 1
duration: 8 sec
s.seconds s.milliseconds
- util util
+ s/s ms/s
---
archive: QAPATH/archives/sample-secs
@@ -68,16 +68,16 @@ HH:MM:SS 1
duration: 7 sec
s.seconds s.milliseconds
- util util
+ s/s ms/s
20:36:45 N/A N/A
20:36:48 N/A N/A
-20:36:51 1.000 1.000
+20:36:51 1.000 999.992
---
N/A N/A
N/A N/A
- 1.000 1.000
- 1.000 1.000
- 1.000 1.000
+ 1.000 1000.033
+ 1.000 1000.001
+ 1.000 1000.016
== exercise non-integer options
archive: QAPATH/archives/sample-secs
@@ -91,13 +91,13 @@ HH:MM:SS 1
duration: 2.500 sec
s.seconds s.milliseconds
- util util
+ s/s ms/s
20:36:45 N/A N/A
20:36:45 N/A N/A
-20:36:46 2.000 1.000
-20:36:46 0.000 1.000
-20:36:47 2.000 1.000
-20:36:47 0.000 1.000
+20:36:46 2.000 1000.216
+20:36:46 0.000 1000.216
+20:36:47 2.000 1000.216
+20:36:47 0.000 1000.205
== exercise raw counter mode
s.seconds s.milliseconds
sec millisec
@@ -108,12 +108,12 @@ HH:MM:SS 1
380440 380439679.413
== exercise timezone setting
s.seconds s.milliseconds
- util util
+ s/s ms/s
10:36:45 N/A N/A
10:36:47 N/A N/A
-10:36:49 1.000 1.000
-10:36:51 1.000 1.000
-10:36:53 1.000 1.000
+10:36:49 1.000 1000.033
+10:36:51 1.000 1000.001
+10:36:53 1.000 1000.016
== exercise CSV and alternate delimiters
Time,sample.seconds,sample.milliseconds
2000-05-01 20:36:45,"",""
@@ -131,15 +131,15 @@ Time|sample.seconds|sample.milliseconds
ok
== exercise repeated headers option
s.seconds
- util
+ s/s
N/A
N/A
s.seconds
- util
+ s/s
1.000
1.000
s.seconds
- util
+ s/s
1.000
== exercise units conversion options
m.u.free m.u.used
@@ -174,23 +174,23 @@ ok
00:47:09 0.000 3000.000 50.000 0.000
0.000 50.000
d.d.avactive d.d.avactive d.d.avactive d.d.avactive
d.d.avactive d.d.avactive
sda sdb sdc hdc
sdd sde
- util util util util
util util
+ s/s s/s s/s s/s
s/s s/s
08:58:23 N/A N/A N/A N/A
N/A N/A
-08:59:23 0.000000 0.000056 0.000006 0.000000
0.000000 0.000005
-09:00:23 0.000004 0.000089 0.000008 0.000000
0.000000 0.000021
-09:01:23 0.000000 0.000175 0.000013 0.000000
0.000000 0.000036
-09:02:23 0.000000 0.000054 0.000003 0.000000
0.000000 0.000005
+08:59:23 0.000200 0.055902 0.005567 0.000000
0.000000 0.004883
+09:00:23 0.003633 0.088769 0.008017 0.000000
0.000000 0.021034
+09:01:23 0.000200 0.175189 0.012884 0.000000
0.000000 0.036451
+09:02:23 0.000217 0.054218 0.002750 0.000000
0.000000 0.005050
d.d.avactive d.d.avactive d.d.avactive d.d.avactive
d.d.avactive d.d.avactive
sda sdb sdc hdc
sdd sde
- util util util util
util util
+ Âs/s Âs/s Âs/s Âs/s
Âs/s Âs/s
08:58:23 N/A N/A N/A N/A
N/A N/A
-08:59:23 0.200005 55.901528 5.566819 0.000000
0.000000 4.883467
-09:00:23 3.633431 88.769056 8.016882 0.000000
0.000000 21.033900
-09:01:23 0.200007 175.189301 12.883772 0.000000
0.000000 36.451242
-09:02:23 0.216672 54.218071 2.750071 0.000000
0.000000 5.050131
+08:59:23 200.005467 55901.527975 5566.818826 0.000000
0.000000 4883.466815
+09:00:23 3633.431133 88769.056034 8016.882454 0.000000
0.000000 21033.899496
+09:01:23 200.006814 175189.301449 12883.772241 0.000000
0.000000 36451.241772
+09:02:23 216.672278 54218.070915 2750.071227 0.000000
0.000000 5050.130798
== derived metrics configuration file
s.combo
- util
+ s/s
N/A
N/A
1.001
@@ -198,7 +198,7 @@ ok
1.001
== derived metrics directly on command line
s.combo
- util
+ s/s
N/A
N/A
1.001
@@ -206,20 +206,20 @@ ok
1.001
== extended existing sample configuration
s.combo s.seconds s.milliseconds
- util util util
+ s/s s/s ms/s
N/A N/A N/A
N/A N/A N/A
- 1.001 1.000 1.000
- 1.001 1.000 1.000
- 1.001 1.000 1.000
+ 1.001 1.000 1000.033
+ 1.001 1.000 1000.001
+ 1.001 1.000 1000.016
== exercise good config version
s.seconds s.milliseconds
- util util
+ s/s ms/s
N/A N/A
N/A N/A
- 1.000 1.000
- 1.000 1.000
- 1.000 1.000
+ 1.000 1000.033
+ 1.000 1000.001
+ 1.000 1000.016
== exercise bad config version
Incompatible configuration file version (read v99, need v1).
== un/interpolated archive mode reporting
diff --git a/qa/1071.out b/qa/1071.out
index 738e589..5beab6f 100644
--- a/qa/1071.out
+++ b/qa/1071.out
@@ -17,6 +17,7 @@ QA output created by 1071
14:39:14 Linux linux 15707 13573328 0
507689 8 16053852 3
14:39:15 Linux linux 15707 13573256 0
507691 8 16053852 3
14:39:16 Linux linux 15708 13573256 0
507692 8 16053852 3
+14:39:17 N/A linux N/A N/A N/A
N/A 8 16053852 3
archive: QAPATH/archives/rep
host: slack
@@ -30,11 +31,12 @@ QA output created by 1071
p.p.start_ti n.i.baudrate k.a.hz d.a.read_byt k.a.sysfork
k.p.c.user k.a.load h.c.bogomips h.c.clock n.i.speed
000001 /usr/ enp0s25
cpu0 1 minute cpu0 cpu0 enp0s25
- millisec byte/s count/s Kbyte/s count/s
util count Mbyte/s
+ millisec byte/s count/s Kbyte/s count/s
ms/s count Mbyte/s
14:39:13 20 3168713760 100 N/A N/A
N/A 0.0900 5587.4199 3029.0310 781261.9375
14:39:14 20 3168713760 100 0.0000 0.0000
0.0000 0.0900 5587.4199 3029.0310 781261.9375
14:39:15 20 3168713760 100 0.0000 0.0000
0.0000 0.0800 5587.4199 2800.0000 781261.9375
-14:39:16 20 3168713760 100 0.0000 1.0000
0.0100 0.0800 5587.4199 2800.0000 781261.9375
+14:39:16 20 3168713760 100 0.0000 1.0000
10.0000 0.0800 5587.4199 2800.0000 781261.9375
+14:39:17 20 3168713760 100 N/A N/A
N/A N/A 5587.4199 2800.1089 781261.9375
== testing raw metrics reporting
archive: QAPATH/archives/rep
@@ -53,6 +55,7 @@ QA output created by 1071
14:39:14 Linux linux 15707 13573328 0
507689 8 16053852 3
14:39:15 Linux linux 15707 13573256 0
507691 8 16053852 3
14:39:16 Linux linux 15708 13573256 0
507692 8 16053852 3
+14:39:17 N/A linux N/A N/A N/A
N/A 8 16053852 3
archive: QAPATH/archives/rep
host: slack
@@ -71,6 +74,7 @@ QA output created by 1071
14:39:14 20 3168713760 100 8736634 3995200
4349650 0.0900 5587.4199 3029.0310 781261.9375
14:39:15 20 3168713760 100 8736634 3995200
4349650 0.0800 5587.4199 2800.0000 781261.9375
14:39:16 20 3168713760 100 8736634 3995201
4349660 0.0800 5587.4199 2800.0000 781261.9375
+14:39:17 20 3168713760 100 N/A N/A
N/A N/A 5587.4199 2800.1089 781261.9375
== testing uninterpolated metrics reporting
archive: QAPATH/archives/rep
@@ -103,11 +107,11 @@ QA output created by 1071
p.p.start_ti n.i.baudrate k.a.hz d.a.read_byt k.a.sysfork
k.p.c.user k.a.load h.c.bogomips h.c.clock n.i.speed
000001 /usr/ enp0s25
cpu0 1 minute cpu0 cpu0 enp0s25
- millisec byte/s count/s Kbyte/s count/s
util count Mbyte/s
+ millisec byte/s count/s Kbyte/s count/s
ms/s count Mbyte/s
14:39:13 20 3168713760 100 N/A N/A
N/A 0.0900 5587.4199 3029.0310 781261.9375
14:39:14 20 3168713760 100 0.0000 0.0000
0.0000 0.0900 5587.4199 2723.4370 781261.9375
14:39:15 20 3168713760 100 0.0000 0.0000
0.0000 0.0800 5587.4199 2800.0000 781261.9375
-14:39:16 20 3168713760 100 0.0000 0.9999
0.0100 0.0800 5587.4199 2800.0000 781261.9375
+14:39:16 20 3168713760 100 0.0000 0.9999
9.9987 0.0800 5587.4199 2800.0000 781261.9375
14:39:17 20 3168713760 100 0.0000 2.0002
0.0000 0.0800 5587.4199 2800.1089 781261.9375
== testing uninterpolated raw metrics reporting
diff --git a/src/pmrep/pmrep.1 b/src/pmrep/pmrep.1
index 2e91f92..ccccf6e 100644
--- a/src/pmrep/pmrep.1
+++ b/src/pmrep/pmrep.1
@@ -173,6 +173,16 @@ Too-wide numeric values for output will not be printed
(apart from
decimal places, numeric values will never be silently truncated).
Too-wide strings will be truncated.
.P
+As a special case with metrics that are counters with time units
+(nanoseconds to hours), the
+.I unit/scale
+can be used to change the default reporting (for example,
+milliseconds / second) to normalize to the range zero to one
+by setting this to
+.B sec
+(see also
+.BR -y ).
+.P
The following
.I metricspec
requests the metric
@@ -240,7 +250,8 @@ for space (byte) metrics, possible values include
.BR Mbytes ,
.BR MB ,
and so forth up to
-.BR Ebytes .
+.BR Ebytes ,
+.BR EB .
This option will
.I not
override possible per-metric specifications.
@@ -583,8 +594,9 @@ for time metrics, possible values include
.BR microsec ,
.BR us ,
.BR millisec ,
+.BR ms ,
and so forth up to
-.BR hours ,
+.BR hour ,
.BR hr .
This option will
.I not
diff --git a/src/pmrep/pmrep.conf b/src/pmrep/pmrep.conf
index 4c9949b..d31e483 100644
--- a/src/pmrep/pmrep.conf
+++ b/src/pmrep/pmrep.conf
@@ -96,20 +96,25 @@ mem.vmstat.pgpgout = bo,,,,6
kernel.all.intr = in,,,,6
kernel.all.pswitch = cs,,,,6
alluser = kernel.all.cpu.alluserp
-alluser.formula = 100 * (kernel.all.cpu.user + kernel.all.cpu.nice) / hinv.ncpu
alluser.label = us
+alluser.formula = 100 * (kernel.all.cpu.user + kernel.all.cpu.nice) / hinv.ncpu
+alluser.unit = s
sys = kernel.all.cpu.sysp
sys.label = sy
sys.formula = 100 * kernel.all.cpu.sys / hinv.ncpu
+sys.unit = s
idle = kernel.all.cpu.idlep
idle.label = id
idle.formula = 100 * kernel.all.cpu.idle / hinv.ncpu
+idle.unit = s
wtotal = kernel.all.cpu.wait.totalp
wtotal.label = wa
wtotal.formula = 100 * kernel.all.cpu.wait.total / hinv.ncpu
+wtotal.unit = s
steal = kernel.all.cpu.stealp
steal.label = st
steal.formula = 100 * kernel.all.cpu.steal / hinv.ncpu
+steal.unit = s
# An example metric set
[example-1]
diff --git a/src/pmrep/pmrep.py b/src/pmrep/pmrep.py
index e548729..5f2b67d 100755
--- a/src/pmrep/pmrep.py
+++ b/src/pmrep/pmrep.py
@@ -218,16 +218,14 @@ class PMReporter(object):
# Performance metrics store
# key - metric name
- # values - 0:label, 1:instance(s), 2:unit/scale, 3:type, 4:width
+ # values - 0:label, 1:instance(s), 2:unit/scale, 3:type, 4:width,
5:pmfg item
self.metrics = OrderedDict()
+ self.pmfg = None
+ self.pmfg_ts = None
# Corresponding config file metric specifiers
self.metricspec = ('label', 'instance', 'unit', 'type', 'width',
'formula')
- self.prevvals = None
- self.currvals = None
- self.ptstamp = 0
- self.ctstamp = 0
self.pmids = []
self.descs = []
self.insts = []
@@ -565,7 +563,10 @@ class PMReporter(object):
self.opts.pmSetOptionFlags(flags | pmapi.c_api.PM_OPTFLAG_DONE)
pmapi.c_api.pmEndOptions()
- self.context = pmapi.pmContext(context, self.source)
+ if not self.source: self.source = "@" # XXX
+ self.pmfg = pmapi.fetchgroup(context, self.source)
+ self.pmfg_ts = self.pmfg.extend_timestamp()
+ self.context = self.pmfg.get_context()
if pmapi.c_api.pmSetContextOptions(self.context.ctx, self.opts.mode,
self.opts.delta):
raise pmapi.pmUsageErr()
@@ -653,9 +654,11 @@ class PMReporter(object):
def format_metric_label(self, label):
""" Format a metric label """
# See src/libpcp/src/units.c
- label = label.replace(" / nanosec", "/ns").replace(" / microsec",
"/Âs")
- label = label.replace(" / millisec", "/ms").replace(" / sec", "/s")
- label = label.replace(" / min", "/min").replace(" / hour", "/h")
+ if ' / ' in label:
+ label = label.replace("nanosec", "ns").replace("microsec", "Âs")
+ label = label.replace("millisec", "ms").replace("sec", "s")
+ label = label.replace("min", "min").replace("hour", "h")
+ label = label.replace(" / ", "/")
return label
def validate_metrics(self):
@@ -719,7 +722,7 @@ class PMReporter(object):
# Finalize the metrics set
for i, metric in enumerate(self.metrics):
# Fill in all fields for easier checking later
- for index in range(0, 5):
+ for index in range(0, 6):
if len(self.metrics[metric]) <= index:
self.metrics[metric].append(None)
@@ -732,7 +735,10 @@ class PMReporter(object):
self.metrics[metric][0] = name[:-2] + m
# Rawness
- if self.metrics[metric][3] == 'raw' or self.type == 1:
+ if self.metrics[metric][3] == 'raw' or self.type == 1 or \
+ self.output == OUTPUT_ARCHIVE or \
+ self.output == OUTPUT_CSV or \
+ self.output == OUTPUT_ZABBIX:
self.metrics[metric][3] = 1
else:
self.metrics[metric][3] = 0
@@ -764,15 +770,16 @@ class PMReporter(object):
if not done:
self.metrics[metric][2] = unitstr
# Set unit/scale for non-raw numeric metrics
+ mtype = None
try:
if self.metrics[metric][3] == 0 and \
self.descs[i].contents.type != PM_TYPE_STRING:
(unitstr, mult) =
self.context.pmParseUnitsStr(self.metrics[metric][2])
label = self.metrics[metric][2]
if self.descs[i].sem == PM_SEM_COUNTER:
- label += "/s"
- if self.descs[i].contents.units.dimTime == 1:
- label = "util"
+ mtype = PM_TYPE_DOUBLE
+ if '/' not in label:
+ label += " / s"
label = self.format_metric_label(label)
self.metrics[metric][2] = (label, unitstr, mult)
else:
@@ -792,16 +799,12 @@ class PMReporter(object):
if self.metrics[metric][4] < len(TRUNC):
self.metrics[metric][4] = len(TRUNC) # Forced minimum
- # RHBZ#1264147
- def pmids_to_ctypes(self, pmids):
- """ Convert a Python list of pmids (numbers) to
- a ctypes LP_c_uint (a C array of uints).
- """
- from ctypes import c_uint
- pmidA = (c_uint * len(pmids))()
- for i, p in enumerate(pmids):
- pmidA[i] = c_uint(p)
- return pmidA
+ # Add fetchgroup item
+ scale = self.metrics[metric][2][0].replace("Âs", "microsec")
+ ins = 1 if self.insts[i][0][0] == PM_IN_NULL else
len(self.insts[i][0])
+ self.metrics[metric][5] = []
+ for j in range(ins):
+ self.metrics[metric][5].append(self.pmfg.extend_item(metric,
mtype, scale, self.insts[i][1][j]))
def get_local_tz(self, set_dst=-1):
""" Figure out the local timezone using the PCP convention """
@@ -906,143 +909,44 @@ class PMReporter(object):
lines = 0
while self.samples != 0:
+ # Repeat the header if needed
if self.output == OUTPUT_STDOUT:
if lines > 1 and self.repeat_header == lines:
self.write_header()
lines = 0
lines += 1
+ # Fetch values
try:
- result = self.context.pmFetch(self.pmids_to_ctypes(self.pmids))
+ self.pmfg.fetch()
except pmapi.pmErr as error:
if error.args[0] == PM_ERR_EOL:
break
raise error
- self.extract(result)
- if self.ctstamp == 0:
- self.ctstamp = copy.copy(result.contents.timestamp)
- self.ptstamp = self.ctstamp
- self.ctstamp = copy.copy(result.contents.timestamp)
-
- if self.context.type == PM_CONTEXT_ARCHIVE:
- if float(self.ctstamp) < float(self.opts.pmGetOptionOrigin()):
- self.context.pmFreeResult(result)
- continue
- if float(self.ctstamp) > float(self.opts.pmGetOptionFinish()):
- self.context.pmFreeResult(result)
- break
- self.report(self.ctstamp, self.currvals)
- self.context.pmFreeResult(result)
+ # Report and prepare for the next round
+ self.report(self.pmfg_ts())
if self.samples and self.samples > 0:
self.samples -= 1
if self.delay and self.interpol and self.samples != 0:
self.context.pmtimevalSleep(self.interval)
# Allow modules to flush buffered values / say goodbye
- self.report(None, None)
-
- def extract(self, result):
- """ Extract the metric values from pmResult structure """
- # Metrics incl. all instance values, must match self.format on return
- values = []
-
- for i, metric in enumerate(self.metrics):
- # Per-metric values incl. all instance values
- # We use dict to make it easier to deal with gone/unknown instances
- values.append({})
-
- # Populate instance fields to have values for unavailable instances
- # Values are (instance id, instance name, instance value)
- for inst in self.insts[i][0]:
- values[i][inst] = (-1, None, NO_VAL)
-
- # No values available for this metric
- if result.contents.get_numval(i) == 0:
- continue
-
- # Process all fetched instances
- for j in range(result.contents.get_numval(i)):
- inst = result.contents.get_inst(i, j)
-
- # Locate the correct instance and its position
- if inst >= 0:
- if inst not in self.insts[i][0]:
- # Ignore newly emerged instances
- continue
- k = 0
- while inst != self.insts[i][0][k]:
- k += 1
+ self.report(None)
- # Extract and scale the value
- try:
- # Use native type if no rescaling needed
- if self.descs[i].contents.type == PM_TYPE_STRING or \
- self.metrics[metric][3] == 1 or \
- (self.metrics[metric][2][2] == 1 and \
- str(self.descs[i].contents.units) == \
- str(self.metrics[metric][2][1])):
- rescale = 0
- vtype = self.descs[i].contents.type
- else:
- rescale = 1
- vtype = PM_TYPE_DOUBLE
-
- atom = self.context.pmExtractValue(
- result.contents.get_valfmt(i),
- result.contents.get_vlist(i, j),
- self.descs[i].contents.type,
- vtype)
-
- if rescale:
- atom = self.context.pmConvScale(
- vtype,
- atom, self.descs, i,
- self.metrics[metric][2][1])
-
- val = atom.dref(vtype)
-
- if rescale:
- val *= self.metrics[metric][2][2]
- val = int(val) if val == int(val) else val
-
- if inst >= 0:
- values[i][inst] = (inst, self.insts[i][1][k], val)
- else:
- values[i][PM_IN_NULL] = (-1, None, val)
-
- except pmapi.pmErr as error:
- sys.stderr.write("%s: %s, aborting.\n" % (metric,
str(error)))
- sys.exit(1)
-
- # Convert dicts to lists
- vals = []
- for v in values:
- vals.append(v.values())
- values = vals
-
- # Store current and previous values
- # Output modules need to handle non-existing self.prevvals
- self.prevvals = self.currvals
- self.currvals = values
-
- def report(self, tstamp, values):
+ def report(self, tstamp):
""" Report the metric values """
if tstamp != None:
- ts = self.context.pmLocaltime(tstamp.tv_sec)
- us = int(tstamp.tv_usec)
- dt = datetime(ts.tm_year+1900, ts.tm_mon+1, ts.tm_mday,
- ts.tm_hour, ts.tm_min, ts.tm_sec, us, None)
- tstamp = dt.strftime(self.timefmt)
+ tstamp = tstamp.strftime(self.timefmt)
if self.output == OUTPUT_ARCHIVE:
- self.write_archive(tstamp, values)
+ self.write_archive(tstamp)
if self.output == OUTPUT_CSV:
- self.write_csv(tstamp, values)
+ self.write_csv(tstamp)
if self.output == OUTPUT_STDOUT:
- self.write_stdout(tstamp, values)
+ self.write_stdout(tstamp)
if self.output == OUTPUT_ZABBIX:
- self.write_zabbix(tstamp, values)
+ self.write_zabbix(tstamp)
def prepare_writer(self):
""" Prepare generic stdout writer """
@@ -1112,10 +1016,8 @@ class PMReporter(object):
duration = int(duration) if duration == int(duration) else
"{0:.3f}".format(duration)
if self.context.type == PM_CONTEXT_ARCHIVE:
- if not self.interpol:
- endtime = float(self.context.pmGetArchiveEnd())
if endtime > float(self.context.pmGetArchiveEnd()):
- endtime = float(self.context.pmGetArchiveEnd())
+ endtime = self.context.pmGetArchiveEnd()
if not self.interpol and self.opts.pmGetOptionSamples():
samples = str(samples) + " (requested)"
elif not self.interpol:
@@ -1191,7 +1093,7 @@ class PMReporter(object):
if self.context.type == PM_CONTEXT_ARCHIVE:
self.delay = 0
self.interpol = 0
- self.zabbix_interval = 250 # See zabbix_sender(8),
pmrep.conf(5)
+ self.zabbix_interval = 250 # See zabbix_sender(8)
self.writer.write("Sending %d archived metrics to Zabbix
server %s...\n(Ctrl-C to stop)\n" % (len(self.pmids), self.zabbix_server))
return
@@ -1204,9 +1106,9 @@ class PMReporter(object):
else:
self.writer.write("...\n(Ctrl-C to stop)\n")
- def write_archive(self, timestamp, values):
+ def write_archive(self, timestamp):
""" Write an archive record """
- if timestamp == None and values == None:
+ if timestamp == None:
# Complete and close
self.pmi.pmiEnd()
self.pmi = None
@@ -1238,25 +1140,27 @@ class PMReporter(object):
for i, metric in enumerate(self.metrics):
ins = 1 if self.insts[i][0][0] == PM_IN_NULL else
len(self.insts[i][0])
for j in range(ins):
- if str(list(values[i])[j][2]) != NO_VAL:
- data = 1
+ try:
+ value = self.metrics[metric][5][j]()
inst = self.insts[i][1][j]
+ data = 1
if self.descs[i].contents.type == PM_TYPE_STRING:
- self.pmi.pmiPutValue(metric, inst,
str(list(values[i])[j][2]))
+ self.pmi.pmiPutValue(metric, inst, value)
elif self.descs[i].contents.type == PM_TYPE_FLOAT or \
self.descs[i].contents.type == PM_TYPE_DOUBLE:
- self.pmi.pmiPutValue(metric, inst, "%f" %
list(values[i])[j][2])
+ self.pmi.pmiPutValue(metric, inst, "%f" % value)
else:
- self.pmi.pmiPutValue(metric, inst, "%d" %
list(values[i])[j][2])
+ self.pmi.pmiPutValue(metric, inst, "%d" % value)
+ except:
+ pass
# Flush
if data:
- # pylint: disable=maybe-no-member
- self.pmi.pmiWrite(self.ctstamp.tv_sec, self.ctstamp.tv_usec)
+ self.pmi.pmiWrite(int(self.pmfg_ts().strftime('%s')),
self.pmfg_ts().microsecond)
- def write_csv(self, timestamp, values):
+ def write_csv(self, timestamp):
""" Write results in CSV format """
- if timestamp == None and values == None:
+ if timestamp == None:
# Silent goodbye
return
@@ -1266,7 +1170,10 @@ class PMReporter(object):
ins = 1 if self.insts[i][0][0] == PM_IN_NULL else
len(self.insts[i][0])
for j in range(ins):
line += self.delimiter
- value = list(values[i])[j][2]
+ try:
+ value = self.metrics[metric][5][j]()
+ except:
+ value = NO_VAL
if type(value) is float:
fmt = "." + str(self.precision) + "f"
line += format(value, fmt)
@@ -1281,9 +1188,9 @@ class PMReporter(object):
line += str("\"" + value + "\"")
self.writer.write(line + "\n")
- def write_stdout(self, timestamp, values):
+ def write_stdout(self, timestamp):
""" Write a line to stdout """
- if timestamp == None and values == None:
+ if timestamp == None:
# Silent goodbye
return
@@ -1301,29 +1208,13 @@ class PMReporter(object):
for i, metric in enumerate(self.metrics):
l = self.metrics[metric][4]
- for j in range(len(values[i])):
+ for j in range(len(self.metrics[metric][5])):
k += 1
- # Raw or rate
- if self.metrics[metric][3] or \
- self.descs[i].sem != PM_SEM_COUNTER or \
- list(values[i])[j][2] == NO_VAL:
- # Raw
- value = list(values[i])[j][2]
- elif not self.metrics[metric][3] and \
- (self.prevvals == None or list(self.prevvals[i])[j][2] ==
NO_VAL):
- # Rate not yet possible
+ try:
+ value = self.metrics[metric][5][j]()
+ except:
value = NO_VAL
- else:
- # Rate
- scale = 1
- if self.descs[i].contents.units.dimTime != 0:
- if self.descs[i].contents.units.scaleTime >
PM_TIME_SEC:
- scale = pow(60, (PM_TIME_SEC -
self.descs[i].contents.units.scaleTime))
- else:
- scale = pow(1000, (PM_TIME_SEC -
self.descs[i].contents.units.scaleTime))
- delta = scale * (float(self.ctstamp) - float(self.ptstamp))
- value = (list(values[i])[j][2] -
list(self.prevvals[i])[j][2]) / delta if delta else 0
# Make sure the value fits
if type(value) is int or type(value) is long:
@@ -1369,9 +1260,9 @@ class PMReporter(object):
nfmt = nfmt[:-l]
self.writer.write(nfmt.format(*tuple(line)) + "\n")
- def write_zabbix(self, timestamp, values):
+ def write_zabbix(self, timestamp):
""" Write (send) metrics to a Zabbix server """
- if timestamp == None and values == None:
+ if timestamp == None:
# Send any remaining buffered values
if self.zabbix_metrics:
send_to_zabbix(self.zabbix_metrics, self.zabbix_server,
self.zabbix_port)
@@ -1379,7 +1270,7 @@ class PMReporter(object):
return
# Collect the results
- ts = float(self.ctstamp)
+ ts = self.pmfg_ts().timestamp()
if self.zabbix_prevsend == None:
self.zabbix_prevsend = ts
for i, metric in enumerate(self.metrics):
@@ -1388,9 +1279,11 @@ class PMReporter(object):
key = ZBXPRFX + metric
if self.insts[i][1][j]:
key += "[" + str(self.insts[i][1][j]) + "]"
- val = str(list(values[i])[j][2])
- if val != NO_VAL:
- self.zabbix_metrics.append(ZabbixMetric(self.zabbix_host,
key, val, ts))
+ try:
+ value = str(self.metrics[metric][5][j]())
+ self.zabbix_metrics.append(ZabbixMetric(self.zabbix_host,
key, value, ts))
+ except:
+ pass
# Send when needed
if self.context.type == PM_CONTEXT_ARCHIVE:
Thanks,
--
Marko Myllynen
|