pcp
[Top] [All Lists]

pmrep: unify archive recording

To: pcp developers <pcp@xxxxxxxxxxx>
Subject: pmrep: unify archive recording
From: Marko Myllynen <myllynen@xxxxxxxxxx>
Date: Mon, 7 Dec 2015 23:36:13 +0200
Delivered-to: pcp@xxxxxxxxxxx
Organization: Red Hat
Reply-to: myllynen@xxxxxxxxxx
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.4.0
Hi,

even before the first release pmrep already has two archive recording
modes due to "historical reasons" :( I'd rather fix this before the
release. (I used pmcollectl's pmgui based approach as an example
initially but it doesn't cope with the from-archive-to-archive mode so
the pmi based approach was recently added.)

The pmgui method has the tiny "off-sync" issue mentioned earlier [1],
the pmi method doesn't suffer this as it simply skips those records,
apparently to no harm [2].

By switching to pmi in all cases, we can avoid duplication and avoid
this minor issue.

But perhaps most importantly, pmi will output archives not archive
folios (and doesn't create those config/log files) so it should be
easier for users as well.

1) http://oss.sgi.com/pipermail/pcp/2015-November/008741.html
2) http://oss.sgi.com/pipermail/pcp/2015-December/008892.html

---
 src/pmrep/pmrep.1  | 21 +++++--------
 src/pmrep/pmrep.py | 89 +++++++-----------------------------------------------
 2 files changed, 19 insertions(+), 91 deletions(-)

diff --git a/src/pmrep/pmrep.1 b/src/pmrep/pmrep.1
index 36e692c..4c12cea 100644
--- a/src/pmrep/pmrep.1
+++ b/src/pmrep/pmrep.1
@@ -27,7 +27,7 @@
 [\f3\-e\f1 \f2derived\f1]
 [\f3\-E\f1 \f2lines\f1]
 [\f3\-f\f1 \f2precision\f1]
-[\f3\-F\f1 \f2folio\f1]
+[\f3\-F\f1 \f2archive\f1]
 [\f3\-h\f1 \f2host\f1]
 [\f3\-K\f1 \f2spec\f1]
 [\f3\-l\f1 \f2delimiter\f1]
@@ -212,14 +212,9 @@ See also
 .TP
 .B \-\-archive\-folio
 Read metric source archives from the PCP archive
-.IR folio .
-Archive folios are created by
-.BR mkaf (1)
-or by
-.B pmrep
-when using the
-.I archive
-output mode described below.
+.IR folio 
+(see
+.BR mkaf (1)).
 .TP
 .B \-A
 When reporting archived metrics, force the initial sample to be
@@ -296,8 +291,8 @@ does not.
 The default is to use 3 decimal places (when applicable).
 .TP
 .B \-F
-Specify the output archive
-.IR folio .
+Specify the output
+.IR archive .
 See
 .BR \-o .
 .TP
@@ -362,7 +357,7 @@ The available target alternatives are:
 .RS
 .TP 2
 .I archive
-Record metrics into PCP archives which can later be replayed with PCP
+Record metrics into a PCP archive which can later be replayed with PCP
 tools, including
 .B pmrep
 itself. See
@@ -664,7 +659,7 @@ $ pmrep -a ./20150921.09.13 -S @15:00 -T @17:00 :sar-w 
:sar-W
 .PP
 Record all 389 Directory Server, XFS file system and CPU/disk/memory
 related metrics every five seconds for the next five minutes to the PCP
-archive folio
+archive
 .IR ./a :
 .RS +1
 .ft CW
diff --git a/src/pmrep/pmrep.py b/src/pmrep/pmrep.py
index 773e368..dfa7c36 100644
--- a/src/pmrep/pmrep.py
+++ b/src/pmrep/pmrep.py
@@ -60,10 +60,9 @@ import sys
 import os
 import re
 
-from pcp import pmapi, pmgui, pmi
+from pcp import pmapi, pmi
 from cpmapi import PM_CONTEXT_ARCHIVE, PM_CONTEXT_HOST, PM_CONTEXT_LOCAL, 
PM_MODE_FORW, PM_MODE_INTERP, PM_ERR_TYPE, PM_ERR_EOL, PM_ERR_NAME, PM_IN_NULL, 
PM_SEM_COUNTER, PM_TIME_MSEC, PM_TIME_SEC, PM_XTB_SET
 from cpmapi import PM_TYPE_32, PM_TYPE_U32, PM_TYPE_64, PM_TYPE_U64, 
PM_TYPE_FLOAT, PM_TYPE_DOUBLE, PM_TYPE_STRING
-from cpmgui import PM_REC_ON, PM_REC_OFF, PM_REC_SETARG
 
 if sys.version_info[0] >= 3:
     long = int
@@ -313,7 +312,7 @@ class PMReporter(object):
         opts.pmSetLongOption("config", 1, "c", "FILE", "config file path")
         opts.pmSetLongOption("check", 0, "C", "", "check config and metrics 
and exit")
         opts.pmSetLongOption("output", 1, "o", "OUTPUT", "output target, one 
of: archive, csv, stdout (default), zabbix")
-        opts.pmSetLongOption("output-archive", 1, "F", "ARCHIVE", "output 
archive/folio (with -o archive)")
+        opts.pmSetLongOption("output-archive", 1, "F", "ARCHIVE", "output 
archive (with -o archive)")
         opts.pmSetLongOption("derived", 1, "e", "FILE|DFNT", "derived metrics 
definitions")
         opts.pmSetLongOptionDebug()        # -D/--debug
         opts.pmSetLongOptionVersion()      # -V/--version
@@ -373,8 +372,8 @@ class PMReporter(object):
                 sys.stderr.write("Invalid output target %s specified.\n" % 
optarg)
                 sys.exit(1)
         elif opt == 'F':
-            if os.path.exists(optarg) or os.path.exists(optarg + ".index"):
-                sys.stderr.write("Archive/folio %s already exists.\n" % optarg)
+            if os.path.exists(optarg + ".index"):
+                sys.stderr.write("Archive %s already exists.\n" % optarg)
                 sys.exit(1)
             self.archive = optarg
         elif opt == 'e':
@@ -565,7 +564,7 @@ class PMReporter(object):
             self.source = "@" # PCPIntro(1), RHBZ#1272082
 
         if self.output == OUTPUT_ARCHIVE and not self.archive:
-            sys.stderr.write("Archive/folio must be defined with archive 
output.\n")
+            sys.stderr.write("Archive must be defined with archive output.\n")
             sys.exit(1)
 
         if self.output == OUTPUT_ZABBIX and (not self.zabbix_server or \
@@ -811,12 +810,6 @@ class PMReporter(object):
         if self.check == 1:
             return
 
-        # Archive recording from non-archive is handled separately
-        if self.output == OUTPUT_ARCHIVE:
-            if self.context.type != PM_CONTEXT_ARCHIVE:
-                self.write_archive_pmgui()
-                return
-
         # Archive fetching mode
         if self.context.type == PM_CONTEXT_ARCHIVE:
             (mode, step) = self.get_mode_step()
@@ -957,7 +950,7 @@ class PMReporter(object):
             tstamp = dt.strftime(self.timefmt)
 
         if self.output == OUTPUT_ARCHIVE:
-            self.write_archive_pmi(tstamp, values)
+            self.write_archive(tstamp, values)
         if self.output == OUTPUT_CSV:
             self.write_csv(tstamp, values)
         if self.output == OUTPUT_STDOUT:
@@ -1059,12 +1052,12 @@ class PMReporter(object):
     def write_header(self):
         """ Write metrics header """
         if self.output == OUTPUT_ARCHIVE:
-            sys.stdout.write("Recording archive/folio %s" % self.archive)
+            sys.stdout.write("Recording archive %s" % self.archive)
             if self.runtime != -1:
-                sys.stdout.write(":\n%s samples(s) with %.1f sec interval ~ %d 
sec duration.\n" % (self.samples, float(self.interval), self.runtime + 1))
+                sys.stdout.write(":\n%s samples(s) with %.1f sec interval ~ %d 
sec duration.\n" % (self.samples, float(self.interval), self.runtime))
             elif self.samples:
                 duration = (self.samples - 1) * int(self.interval)
-                sys.stdout.write(":\n%s samples(s) with %.1f sec interval ~ %d 
sec duration.\n" % (self.samples, float(self.interval), duration + 1))
+                sys.stdout.write(":\n%s samples(s) with %.1f sec interval ~ %d 
sec duration.\n" % (self.samples, float(self.interval), duration))
             else:
                 if self.context.type != PM_CONTEXT_ARCHIVE:
                     sys.stdout.write("... (Ctrl-C to stop)")
@@ -1124,68 +1117,8 @@ class PMReporter(object):
             else:
                 sys.stdout.write("...\n(Ctrl-C to stop)\n")
 
-    def write_archive_pmgui(self):
-        """ Write archive using pmgui """
-        # We're not a graphical app, disable popups
-        os.environ['PCP_XCONFIRM_PROG'] = '/bin/true'
-
-        # Derived metrics need to be passed to pmlogger(1) via env/file
-        if self.derived:
-            if self.derived.startswith("/") or self.derived.startswith("."):
-                if not os.environ.get('PCP_DERIVED_CONFIG'):
-                    os.environ['PCP_DERIVED_CONFIG'] = self.derived
-                else:
-                    os.environ['PCP_DERIVED_CONFIG'] = 
os.environ['PCP_DERIVED_CONFIG'] + ":" + self.derived
-            else:
-                drvf = self.archive + ".derived"
-                if os.path.exists(drvf):
-                    sys.stderr.write("Derived metrics configuration file %s 
already exists.\n" % drvf)
-                    sys.exit(1)
-                drv = open(drvf, "a+")
-                for definition in self.derived.split(","):
-                    drv.write(definition.strip() + "\n")
-                drv.close()
-                if not os.environ.get('PCP_DERIVED_CONFIG'):
-                    os.environ['PCP_DERIVED_CONFIG'] = drvf
-                else:
-                    os.environ['PCP_DERIVED_CONFIG'] = 
os.environ['PCP_DERIVED_CONFIG'] + ":" + drvf
-
-        # Create the archive folio using pmgui
-        context = pmgui.GuiClient()
-        config = "log mandatory on every " + str(int(self.interval)) + " sec 
{\n"
-        for metric in self.metrics:
-            config += metric + "\n"
-        config += "}\n"
-        context.pmRecordSetup(self.archive, ' '.join(sys.argv), 0)
-        context.pmRecordAddHost(self.source, 1, config)
-        duration = 0
-        if self.runtime != -1:
-            duration = self.runtime
-        elif self.samples:
-            if self.samples < 2:
-                self.samples = 2
-            duration = (self.samples - 1) * int(self.interval)
-        if duration:
-            endtime = "-T" + str(duration) + "sec"
-            context.pmRecordControl(0, PM_REC_SETARG, endtime)
-        context.pmRecordControl(0, PM_REC_ON, "")
-        if not duration:
-            time.sleep(0xFFFFFFFF) # A very long time
-            context.pmRecordControl(0, PM_REC_OFF, "") # Non-mandatory
-            return
-        for i in range(duration):
-            sys.stdout.write("\rProgress: %3d%%" % int(float(i) / duration * 
100))
-            sys.stdout.flush()
-            time.sleep(1)
-        sys.stdout.write("\rProgress:  99%")
-        sys.stdout.flush()
-        time.sleep(1) # Make sure the last record gets there
-        # For cleanliness only, -T should have stopped recording by now
-        context.pmRecordControl(0, PM_REC_OFF, "")
-        sys.stdout.write("\rComplete: 100%.\n")
-
-    def write_archive_pmi(self, timestamp, values):
-        """ Write an archive record using pmi """
+    def write_archive(self, timestamp, values):
+        """ Write an archive record """
         if timestamp == None and values == None:
             # Complete and close
             self.log.pmiEnd()

Thanks,

-- 
Marko Myllynen

<Prev in Thread] Current Thread [Next in Thread>
  • pmrep: unify archive recording, Marko Myllynen <=