Add metrics to the framework 29/4429/3 2.1.0
authorE. Scott Daniels <daniels@research.att.com>
Wed, 22 Jul 2020 19:49:54 +0000 (15:49 -0400)
committerE. Scott Daniels <daniels@research.att.com>
Thu, 23 Jul 2020 11:18:41 +0000 (07:18 -0400)
This change adds support for a metrics class which provides
the API allowing an xAPP to easily create and send a set of
measurements to a central collector for forwarding.

Issue-ID: RIC381

Signed-off-by: E. Scott Daniels <daniels@research.att.com>
Change-Id: I0926b26d4862df308ab0863260805fe057785bdc

24 files changed:
CHANGES
CMakeLists.txt
doc/src/.gitignore [new file with mode: 0644]
doc/src/rtd/rel-notes.rst [deleted file]
doc/src/user/Makefile
doc/src/user/example2.im
doc/src/user/metrics.im [new file with mode: 0644]
doc/src/user/user_guide.xfm
docs/rel-notes.rst
docs/user-guide.rst
examples/Makefile
examples/xapp_t1.cpp
src/json/jwrapper.c
src/messaging/CMakeLists.txt
src/messaging/message.cpp
src/messaging/messenger.cpp
src/messaging/messenger.hpp
src/metrics/CMakeLists.txt [new file with mode: 0644]
src/metrics/metrics.cpp [new file with mode: 0644]
src/metrics/metrics.hpp [new file with mode: 0644]
test/Makefile
test/metrics_test.cpp [new file with mode: 0644]
test/unit_test.cpp
test/unit_test.sh

diff --git a/CHANGES b/CHANGES
index b856218..8663e5a 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -6,6 +6,9 @@
 # squished to one.
 
 release = Cherry
+2020 July 22; version 2.1.0
+       Added metrics support (RIC-381).
+
 2020 July 17; version 2.0.0
        Add alarm support.
 
index 949b158..308c524 100644 (file)
@@ -29,7 +29,7 @@ project( ricxfcpp )
 cmake_minimum_required( VERSION 3.5 )
 
 set( major_version "2" )               # should be automatically populated from git tag later, but until CI process sets a tag we use this
-set( minor_version "0" )
+set( minor_version "1" )
 set( patch_level "0" )
 
 set( install_root "${CMAKE_INSTALL_PREFIX}" )
@@ -156,7 +156,7 @@ set ( srcd "${CMAKE_CURRENT_SOURCE_DIR}" )
 # but Cmake insists on having these exist when we add them to include directories to
 # enable code to find them after we build them.
 #
-include_directories( "${srcd}/src/messaging;${srcd}/src/json;${srcd}/src/alarm;${srcd}/ext/jsmn" )
+include_directories( "${srcd}/src/messaging;${srcd}/src/json;${srcd}/src/alarm;${srcd}/src/metrics;${srcd}/ext/jsmn" )
 
 # Compiler flags
 #
@@ -186,12 +186,13 @@ add_subdirectory( src/json )
 add_subdirectory( src/messaging )
 add_subdirectory( src/xapp )
 add_subdirectory( src/alarm )
+add_subdirectory( src/metrics )
 #add_subdirectory( doc )                               # this will auto skip if {X}fm is not available
 
 # shared and static libraries are built from the same object files.
 #
 add_library( ricxfcpp_shared SHARED
-       "$<TARGET_OBJECTS:message_objects>;$<TARGET_OBJECTS:json_objects>;$<TARGET_OBJECTS:alarm_objects>;$<TARGET_OBJECTS:xapp_objects>"
+       "$<TARGET_OBJECTS:message_objects>;$<TARGET_OBJECTS:json_objects>;$<TARGET_OBJECTS:alarm_objects>;$<TARGET_OBJECTS:metrics_objects>;$<TARGET_OBJECTS:xapp_objects>"
 )
 set_target_properties( ricxfcpp_shared
        PROPERTIES
@@ -199,12 +200,12 @@ set_target_properties( ricxfcpp_shared
        SOVERSION ${major_version}
        VERSION ${major_version}.${minor_version}.${patch_level}
 )
-target_include_directories( ricxfcpp_shared PUBLIC "src/messenger" "src/xapp" )
+#target_include_directories( ricxfcpp_shared PUBLIC "src/alarm" "src/metrics" "src/messenger" "src/xapp" )
 
 # we only build/export the static archive (.a) if generating a dev package
 if( DEV_PKG )
        add_library( ricxfcpp_static STATIC
-               "$<TARGET_OBJECTS:message_objects>;$<TARGET_OBJECTS:json_objects>;$<TARGET_OBJECTS:xapp_objects>"
+               "$<TARGET_OBJECTS:message_objects>;$<TARGET_OBJECTS:json_objects>;$<TARGET_OBJECTS:alarm_objects>;$<TARGET_OBJECTS:metrics_objects>;$<TARGET_OBJECTS:xapp_objects>"
        )
        set_target_properties( ricxfcpp_static
                PROPERTIES
@@ -212,14 +213,14 @@ if( DEV_PKG )
                SOVERSION ${major_version}
                VERSION ${major_version}.${minor_version}.${patch_level}
        )
-       target_include_directories( ricxfcpp_static PUBLIC "src/messenger" "src/xapp" )
+#      target_include_directories( ricxfcpp_static PUBLIC "src/alarm" "src/metrics" "src/messenger" "src/xapp" )
 endif()
 
 # -------- unit testing -------------------------------------------------------
 enable_testing()
 add_test(
        NAME drive_unit_tests
-       COMMAND bash ../test/unit_test.sh -q
+       COMMAND bash ../test/unit_test.sh -q CMBUILD=${CMAKE_CURRENT_BINARY_DIR}
        WORKING_DIRECTORY ../test
 )
 
diff --git a/doc/src/.gitignore b/doc/src/.gitignore
new file mode 100644 (file)
index 0000000..2313f4d
--- /dev/null
@@ -0,0 +1,10 @@
+# don't stash generated things
+*.md
+*.rst
+*.ps
+*.pdf
+
+# don't stash intermediates
+*.sp
+*.ca
+*.bncfile
diff --git a/doc/src/rtd/rel-notes.rst b/doc/src/rtd/rel-notes.rst
deleted file mode 100644 (file)
index 935e799..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-=============
-RELEASE NOTES
-=============
-.. This work is licensed under a Creative Commons Attribution 4.0 International License.
-.. SPDX-License-Identifier: CC-BY-4.0
-..
-.. CAUTION: this document is generated from source in doc/src/*
-.. To make changes edit the source and recompile the document.
-.. Do NOT make changes directly to .rst or .md files.
-
-
-
-C++ Framework Release Notes
-===========================
-The following is a list of release highlights for the C++
-xAPP Framework.
-
-Cherry Release
-==============
-
-2020 July 17; version 2.0.0
----------------------------
-Add alarm support.
-
-Add xapp namespace for Message, Msg_component, Alarm and Jhah
-objects. This is a BREAKING change and thus the major version
-number was bumped to 2.
-
-
-2020 June 29; version 1.2.0
----------------------------
-Add support for json parsing
-
-
-2020 June 26; version 1.1.0
----------------------------
-Change the port type in constructors to indicate "const"
-
-Version bump to 1.1.0 to allow patches to bronze code to
-continue to be done on the 1.0.* level.
-
-
-
-Bronze Release
-==============
-
-2020 April 28; version 1.0.0
-----------------------------
-Bump version to force package build (old CI version added
-incorrect install prefix). Bump to 1.0.0 for release.
-
-
-2020 March 27; version 0.1.2
-----------------------------
-Changes identified by sonar (missing copy/move builders)
-rmr_dump example programme Improvements to code for better
-test coverage
index 303cc20..a300d6c 100644 (file)
@@ -19,7 +19,7 @@
 
 docs = user_guide
 src = user_guide.xfm
-imbed_src = cpp_frame.im example1.im example2.im example3.im jhash.im example4.im
+imbed_src = cpp_frame.im example1.im example2.im example3.im jhash.im example4.im metrics.im
 desired_out = rst ps md
 
 include ../master.mk
index bc1a9fc..b78c6db 100644 (file)
@@ -34,6 +34,12 @@ used, but the programme is &bold(not) thread safe; to keep
 this example as simple as possible, the counters
 are not locked when incremented.
 
+&h2(Metrics Generation)
+The example also illustrates how a metrics object instance can be created
+and used to send appliction metrics to the collector.
+In this example the primary callback function will genereate metrics with
+the receipt of each 1000th message.
+
 &space
 &indent
 .** pull in the code from the example directory
diff --git a/doc/src/user/metrics.im b/doc/src/user/metrics.im
new file mode 100644 (file)
index 0000000..9d13587
--- /dev/null
@@ -0,0 +1,181 @@
+.** vim: sw=4 ts=4 et :
+.if false
+==================================================================================
+    Copyright (c) 2020 AT&T Intellectual Property.
+    Copyright (c) 2020 Nokia
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================================
+.fi
+
+.if false
+    This imbed file contains the description of the metrics API.
+    It should be included by the main user.xfm source.
+.fi
+
+
+&h1(Metrics Support)
+The C++ xAPP framework provides a  lightweight interface to the metrics
+gateway allowing the xAPP to create and send metrics updates without
+needing to understand the underlying message format.
+From the xAPP's perspective, the metrics object is created with one or
+more key/value measurement pairs and then is sent to the process
+responsible for forwarding them to the various collection processes.
+The following sections describe the Metrics object and the API associated
+with it.
+
+
+&h2(Creating The Metrics Object)
+The &cw(xapp:Metrics) object can be created directly, or via the xapp framework.
+When creating directly the xAPP must supply an RMR message for the object to use;
+when the framework is used to create the object, the message is created as
+as part of the process.
+
+The framework provides three constructors for the metrics instance allowing the
+xAPP to supply the measurement source, the source and reporter, or to default to
+using the xAPP name as both the source and reporter (see section &ital( &snr_section )
+for a more detailed description of these).
+The framework constructors are illustrated in figure &frame_builders.
+&space
+
+.ca start frame_builder.ca
+&ex_start
+  std::unique_ptr<xapp::Metrics> Alloc_metrics( );
+  std::unique_ptr<xapp::Metrics> Alloc_metrics( std::string source );
+  std::unique_ptr<xapp::Metrics> Alloc_metrics( std::string reporter, std::string source );
+&ex_end
+&export_fig( frame_builders )
+&fig_cen(The framework constructors for creating an instance of the metrics object.)
+&space
+.ca end
+.gv remain
+&ifroom( 2 : frame_builder.ca )
+
+.ca start create1.ca
+&ex_start
+
+    #include <ricxfcpp/Metrics>
+
+    char* port = (char *) "4560";
+
+    auto x = std::unique_ptr<Xapp>( new Xapp( port ) );
+    auto reading = std::shared_ptr<xapp::Metrics>( x->Alloc_metric( ) );
+&ex_end
+&export_fig( metric_create_1 )
+&fig_cen(Metrics instance creation using the framework. )
+&space
+.ca end
+.gv remain
+&ifroom( 2 : create1.ca )
+
+Figures &metric_create_1 illustrates how the framework constructor can be used to
+create a metrics instance.
+While it is unlikely that an xAPP will create a metrics instance directly, there
+are three similar constructors available.
+These are prototypes are shown in figure &metrics_builders and their use is illustrated
+in figure &metrics_create_2.
+
+.ca start met_builder.ca
+&ex_start
+   Metrics( std::shared_ptr<xapp::Message> msg );
+   Metrics( std::shared_ptr<xapp::Message> msg, std::string msource );
+   Metrics( std::shared_ptr<xapp::Message> msg, std::string reporter, std::string msource );
+&ex_end
+&export_fig( metrics_builders )
+&fig_cen(Metrics object constructors.)
+&space
+.ca end
+.gv remain
+&ifroom( 1 : met_builder.ca )
+
+.ca start create2.ca
+&ex_start
+    #include <ricxfcpp/Metrics>
+
+    char* port = (char *) "4560";
+
+    auto x = std::unique_ptr<Xapp>( new Xapp( port ) );
+    auto msg = std::shared_ptr<xapp::Message>( x->Alloc_msg( 4096 ) );
+    auto reading = std::shared_ptr<xapp::Metrics>( new Metrics( msg ) );
+&ex_end
+&export_fig( metrics_create_2 )
+&fig_cen(Direct creation of a metrics instance.)
+&space
+.ca end
+.gv remain
+&ifroom( 2 : create2.ca )
+
+&h2(Adding Values)
+Once an instance of the metrics object is created, the xAPP may push values in
+preparation to sending the measurement(s) to the collector.
+The &cw(Push_data())  function is used to push each key/value pair and is illustrated
+in figure &push_fig.
+
+.ca start push.ca
+&ex_start
+        reading->Push_data( "normal_count", (double) norm_count );
+        reading->Push_data( "high_count", (double) hi_count );
+        reading->Push_data( "excessive_count", (double) ex_count );
+&ex_end
+&export_fig( push_fig )
+&fig_cen(Pushing key/value pairs into a metrics instance.)
+&space
+.ca end
+.gv remain
+&ifroom( 1 : push.ca )
+
+&h2(Sending A Measurement Set)
+After all of the measurement key/value pairs have been added to the instance, the
+&cw(Send()) function can be invoked to create the necessary RMR message and send that
+to the collection application.
+Following the send, the key/value pairs are cleared from the instance and the
+xAPP is free to start pushing values into the instance again.
+The send function has the following prototype and returns &cw(true) on success and
+&cw(false) if the measurements could not be sent.
+
+&h2(Source and Reporter)
+&export_var( snr_section : Source and Reporter )
+The alarm collector has the understanding that a measurement might be &ital(sourced) from one
+piece of equipment, or software component, but reported by another.
+For auditing purposes it makes sense to distinguish these, and as such the metrics object
+allows the xAPP to identify the case when the source and reporter are something other than
+the xAPP which is generating the metrics message(s).
+
+&space
+The &ital(source) is the component to which the measurement applies.
+This could be a network interface card counting packets, a temperature sensor, or the xAPP
+itself reporting xAPP related metrics.
+The &ital(reporter) is the application that is reporting the measurement(s) to the collector.
+
+&space
+By default, both reporter and source are assumed to be the xAPP, and the name is automatically
+determined using the run-time supplied programme name.
+Should the xAPP need to report measurements for more than one source it has the option to
+create an instance for every reporter source combination, or to set the reporter and/or
+source with the generation of each measurement set.
+To facilitate the ability to change the source and/or the reporter without the need to create
+a new metrics instance, two &ital(setter) functions are provided.
+The prototypes for these are shown in figure &setter_fig.
+&space
+
+.ca start setter.ca
+&ex_start
+    void Set_source( std::string new_source );
+    void Set_reporter( std::string new_reporter );
+&ex_end
+&export_fig( setter_fig )
+&fig_cen( Setter functions allowing the reporter and/or source to be set after construction. )
+&space
+.ca end
+.gv remain
+&ifroom( 1 : setter.ca )
index e6e47f1..9ba1d4a 100644 (file)
@@ -56,6 +56,7 @@
 .im cpp_frame.im
 .im jhash.im
 .im alarm.im
+.im metrics.im
 
 &h1(Example Programmes)
 The following sections contain several example programmes which are written on
index 935e799..4841bcb 100644 (file)
@@ -18,6 +18,11 @@ xAPP Framework.
 Cherry Release
 ==============
 
+2020 July 22; version 2.1.0
+---------------------------
+Added metrics support (RIC-381).
+
+
 2020 July 17; version 2.0.0
 ---------------------------
 Add alarm support.
index 17f741d..f5df1b8 100644 (file)
@@ -931,6 +931,158 @@ Figure 16: Alarm Setters
 
 
 
+METRICS SUPPORT
+===============
+
+The C++ xAPP framework provides a lightweight interface to
+the metrics gateway allowing the xAPP to create and send
+metrics updates without needing to understand the underlying
+message format. From the xAPP's perspective, the metrics
+object is created with one or more key/value measurement
+pairs and then is sent to the process responsible for
+forwarding them to the various collection processes. The
+following sections describe the Metrics object and the API
+associated with it.
+
+
+Creating The Metrics Object
+---------------------------
+
+The ``xapp`` object can be created directly, or via the xapp
+framework. When creating directly the xAPP must supply an RMR
+message for the object to use; when the framework is used to
+create the object, the message is created as as part of the
+process. The framework provides three constructors for the
+metrics instance allowing the xAPP to supply the measurement
+source, the source and reporter, or to default to using the
+xAPP name as both the source and reporter (see section
+*Source and Reporter* for a more detailed description of
+these). The framework constructors are illustrated in figure
+17.
+
+
+::
+
+    std::unique_ptr<xapp::Metrics> Alloc_metrics( );
+    std::unique_ptr<xapp::Metrics> Alloc_metrics( std::string source );
+    std::unique_ptr<xapp::Metrics> Alloc_metrics( std::string reporter, std::string source );
+
+Figure 17: The framework constructors for creating an
+instance of the metrics object.
+
+
+::
+
+
+      #include <ricxfcpp/Metrics>
+
+      char* port = (char *) "4560";
+
+      auto x = std::unique_ptr<Xapp>( new Xapp( port ) );
+      auto reading = std::shared_ptr<xapp::Metrics>( x->Alloc_metric( ) );
+
+Figure 18: Metrics instance creation using the framework.
+
+Figures 18 illustrates how the framework constructor can be
+used to create a metrics instance. While it is unlikely that
+an xAPP will create a metrics instance directly, there are
+three similar constructors available. These are prototypes
+are shown in figure 19 and their use is illustrated in figure
+20.
+
+::
+
+     Metrics( std::shared_ptr<xapp::Message> msg );
+     Metrics( std::shared_ptr<xapp::Message> msg, std::string msource );
+     Metrics( std::shared_ptr<xapp::Message> msg, std::string reporter, std::string msource );
+
+Figure 19: Metrics object constructors.
+
+
+::
+
+      #include <ricxfcpp/Metrics>
+
+      char* port = (char *) "4560";
+
+      auto x = std::unique_ptr<Xapp>( new Xapp( port ) );
+      auto msg = std::shared_ptr<xapp::Message>( x->Alloc_msg( 4096 ) );
+      auto reading = std::shared_ptr<xapp::Metrics>( new Metrics( msg ) );
+
+Figure 20: Direct creation of a metrics instance.
+
+
+
+Adding Values
+-------------
+
+Once an instance of the metrics object is created, the xAPP
+may push values in preparation to sending the measurement(s)
+to the collector. The ``Push_data()`` function is used to
+push each key/value pair and is illustrated in figure 21.
+
+::
+
+          reading->Push_data( "normal_count", (double) norm_count );
+          reading->Push_data( "high_count", (double) hi_count );
+          reading->Push_data( "excessive_count", (double) ex_count );
+
+Figure 21: Pushing key/value pairs into a metrics instance.
+
+
+
+Sending A Measurement Set
+-------------------------
+
+After all of the measurement key/value pairs have been added
+to the instance, the ``Send()`` function can be invoked to
+create the necessary RMR message and send that to the
+collection application. Following the send, the key/value
+pairs are cleared from the instance and the xAPP is free to
+start pushing values into the instance again. The send
+function has the following prototype and returns ``true`` on
+success and ``false`` if the measurements could not be sent.
+
+
+Source and Reporter
+-------------------
+
+The alarm collector has the understanding that a measurement
+might be *sourced* from one piece of equipment, or software
+component, but reported by another. For auditing purposes it
+makes sense to distinguish these, and as such the metrics
+object allows the xAPP to identify the case when the source
+and reporter are something other than the xAPP which is
+generating the metrics message(s).
+
+The *source* is the component to which the measurement
+applies. This could be a network interface card counting
+packets, a temperature sensor, or the xAPP itself reporting
+xAPP related metrics. The *reporter* is the application that
+is reporting the measurement(s) to the collector.
+
+By default, both reporter and source are assumed to be the
+xAPP, and the name is automatically determined using the
+run-time supplied programme name. Should the xAPP need to
+report measurements for more than one source it has the
+option to create an instance for every reporter source
+combination, or to set the reporter and/or source with the
+generation of each measurement set. To facilitate the ability
+to change the source and/or the reporter without the need to
+create a new metrics instance, two *setter* functions are
+provided. The prototypes for these are shown in figure 22.
+
+
+::
+
+      void Set_source( std::string new_source );
+      void Set_reporter( std::string new_reporter );
+
+Figure 22: Setter functions allowing the reporter and/or
+source to be set after construction.
+
+
+
 EXAMPLE PROGRAMMES
 ==================
 
@@ -1200,7 +1352,7 @@ omitted. The full code is in the framework repository.
          return 0;
      }
 
-   Figure 17: Simple callback application.
+   Figure 23: Simple callback application.
 
 
 Callback Receiver
@@ -1222,12 +1374,22 @@ this example as simple as possible, the counters are not
 locked when incremented.
 
 
+Metrics Generation
+------------------
+
+The example also illustrates how a metrics object instance
+can be created and used to send appliction metrics to the
+collector. In this example the primary callback function will
+genereate metrics with the receipt of each 1000th message.
+
+
    ::
 
      #include <stdio.h>
 
      #include "ricxfcpp/message.hpp"
      #include "ricxfcpp/msg_component.hpp"
+     #include <ricxfcpp/metrics.hpp>
      #include "ricxfcpp/xapp.hpp"
 
      // counts; not thread safe
@@ -1238,7 +1400,10 @@ locked when incremented.
      long cb1_lastts = 0;
      long cb1_lastc = 0;
 
-     // respond with 2 messages for each type 1 received
+     /*
+         Respond with 2 messages for each type 1 received
+         Send metrics every 1000 messages.
+     */
      void cb1( xapp::Message& mbuf, int mtype, int subid, int len,
                  xapp::Msg_component payload,  void* data ) {
          long now;
@@ -1249,6 +1414,16 @@ locked when incremented.
          mbuf.Send_response( 101, -1, 5, (unsigned char *) "OK2\\n" );
 
          cb1_count++;
+
+         if( cb1_count % 1000 == 0 && data != NULL ) {   // send metrics every 1000 messages
+             auto x = (Xapp *) data;
+             auto msgm = std::shared_ptr<xapp::Message>( x->Alloc_msg( 4096 ) );
+
+             auto m = std::unique_ptr<xapp::Metrics>( new xapp::Metrics( msgm ) );
+             m->Push_data( "tst_cb1", (double) cb1_count );
+             m->Push_data( "tst_cb2", (double) cb2_count );
+             m->Send();
+         }
      }
 
      // just count messages
@@ -1294,7 +1469,7 @@ locked when incremented.
          fprintf( stderr, "<XAPP> starting %d threads\\n", nthreads );
 
          x = new Xapp( port, true );
-         x->Add_msg_cb( 1, cb1, NULL );                // register callbacks
+         x->Add_msg_cb( 1, cb1, x );        // register callbacks
          x->Add_msg_cb( 2, cb2, NULL );
          x->Add_msg_cb( x->DEFAULT_CALLBACK, cbd, NULL );
 
@@ -1302,7 +1477,7 @@ locked when incremented.
          // control should not return
      }
 
-   Figure 18: Simple callback application.
+   Figure 24: Simple callback application.
 
 
 
@@ -1414,7 +1589,7 @@ to keep the example small and to the point.
          }
      }
 
-   Figure 19: Simple looping sender application.
+   Figure 25: Simple looping sender application.
 
 
 
@@ -1539,6 +1714,6 @@ Alarm Example
             }
         }
 
-      Figure 20: Simple looping sender application with alarm
+      Figure 26: Simple looping sender application with alarm
       generation.
 
index a56760a..2c4ded5 100644 (file)
 # variables are set to reference the needed files.
 
 %.o:: %.cpp %.hpp
-       g++ -g ${prereq%% *} -c 
+       g++ -g ${prereq%% *} -c
 
 % :: %.cpp
+       #C_INCLUDE_PATH=/tmp/usr/include:/usr/local/include g++ $< -g -o $@  -lricxfcpp -lrmr_si -lpthread -lm
        g++ $< -g -o $@  -lricxfcpp -lrmr_si -lpthread -lm
 
 all:: xapp_t1 xapp_t2 rmr_dump
index 5ec8536..0de4e11 100644 (file)
@@ -45,6 +45,7 @@
 
 #include "ricxfcpp/message.hpp"
 #include "ricxfcpp/msg_component.hpp"
+#include <ricxfcpp/metrics.hpp>
 #include "ricxfcpp/xapp.hpp"
 
 // counts; not thread safe
@@ -55,7 +56,10 @@ long cbd_count = 0;
 long cb1_lastts = 0;
 long cb1_lastc = 0;
 
-// respond with 2 messages for each type 1 received
+/*
+       Respond with 2 messages for each type 1 received
+       Send metrics every 1000 messages.
+*/
 void cb1( xapp::Message& mbuf, int mtype, int subid, int len,
                        xapp::Msg_component payload,  void* data ) {
        long now;
@@ -66,6 +70,16 @@ void cb1( xapp::Message& mbuf, int mtype, int subid, int len,
        mbuf.Send_response( 101, -1, 5, (unsigned char *) "OK2\n" );
 
        cb1_count++;
+
+    if( cb1_count % 1000 == 0 && data != NULL ) {   // send metrics every 1000 messages
+        auto x = (Xapp *) data;
+        auto msgm = std::shared_ptr<xapp::Message>( x->Alloc_msg( 4096 ) );
+
+        auto m = std::unique_ptr<xapp::Metrics>( new xapp::Metrics( msgm ) );
+        m->Push_data( "tst_cb1", (double) cb1_count );
+        m->Push_data( "tst_cb2", (double) cb2_count );
+        m->Send();
+    }
 }
 
 // just count messages
@@ -111,7 +125,7 @@ int main( int argc, char** argv ) {
        fprintf( stderr, "<XAPP> starting %d threads\n", nthreads );
 
        x = new Xapp( port, true );
-       x->Add_msg_cb( 1, cb1, NULL );                          // register callbacks
+       x->Add_msg_cb( 1, cb1, x );             // register callbacks
        x->Add_msg_cb( 2, cb2, NULL );
        x->Add_msg_cb( x->DEFAULT_CALLBACK, cbd, NULL );
 
index 3f85a59..f6ce014 100644 (file)
@@ -490,7 +490,7 @@ extern void* jw_new( const char* json ) {
        char*   djson;                          // dup so we can save it
        void*   rp = NULL;                      // return value
 
-       if( json != NULL && (st = rmr_sym_alloc( MAX_THINGS )) != NULL ) {
+       if( json != NULL && (st = rmr_sym_alloc( MAX_THINGS/4 )) != NULL ) {
                djson = strdup( json );                                                                                                 // allows user to free/overlay their buffer as needed
                rp =  parse_jobject( st,  djson, "" );                  // empty prefix for the root object; parse_jo will clean up and free st
                if( rp == NULL ) {
index 507da84..c112a6b 100644 (file)
@@ -22,7 +22,7 @@
 # For clarity: this generates object, not a lib as the CM command implies.
 #
 add_library( message_objects OBJECT
-       callback.cpp    
+       callback.cpp
        default_cb.cpp
        message.cpp
        messenger.cpp
@@ -36,12 +36,12 @@ target_include_directories (message_objects PUBLIC
 # header files should go into .../include/xfcpp/
 if( DEV_PKG )
        install( FILES
-               callback.hpp  
-               default_cb.hpp  
-               message.hpp  
+               callback.hpp
+               default_cb.hpp
+               message.hpp
                messenger.hpp
                msg_component.hpp
                DESTINATION ${install_inc}
-       ) 
+       )
 endif()
 
index 41f5a78..a8b8089 100644 (file)
@@ -152,14 +152,14 @@ xapp::Message::~Message() {
 */
 //char* Message::Copy_payload( ){
 std::unique_ptr<unsigned char> xapp::Message::Copy_payload( ){
-       unsigned char*  new_payload = NULL;
 
        if( mbuf != NULL ) {
-               new_payload = (unsigned char *) malloc( sizeof( unsigned char ) * mbuf->len );
+               unsigned char*  new_payload = new unsigned char[mbuf->len];
                memcpy( new_payload, mbuf->payload, mbuf->len );
+               return std::unique_ptr<unsigned char>( new_payload );
        }
 
-       return std::unique_ptr<unsigned char>( new_payload );
+       return NULL;
 }
 
 /*
@@ -198,10 +198,7 @@ int        xapp::Message::Get_mtype(){
        Makes a copy of the source field and returns a smart pointer to it.
 */
 std::unique_ptr<unsigned char> xapp::Message::Get_src(){
-       unsigned char* m = NULL;
-
-       m = (unsigned char *) malloc( sizeof( unsigned char ) * RMR_MAX_SRC );
-       memset( m, 0, sizeof( unsigned char ) * RMR_MAX_SRC );
+       unsigned char* m = new unsigned char[RMR_MAX_SRC]; 
 
        if( m != NULL ) {
                rmr_get_src( mbuf, m );
index 67d5e2d..ede76d3 100644 (file)
@@ -44,6 +44,7 @@
 #include "message.hpp"
 #include "messenger.hpp"
 #include "alarm.hpp"
+#include "metrics.hpp"
 
 namespace xapp {
 
@@ -200,6 +201,28 @@ std::unique_ptr<xapp::Alarm> xapp::Messenger::Alloc_alarm( ) {
 }
 
 
+// ------------------ metrics support --------------------------------------------------
+std::unique_ptr<xapp::Metrics> xapp::Messenger::Alloc_metrics( ) {
+       std::shared_ptr<Message> m;
+
+       m = Alloc_msg( 4096 );
+       return std::unique_ptr<xapp::Metrics>( new xapp::Metrics( m ) );
+}
+
+std::unique_ptr<xapp::Metrics> xapp::Messenger::Alloc_metrics( std::string source ) {
+       std::shared_ptr<Message> m;
+
+       m = Alloc_msg( 4096 );
+       return std::unique_ptr<xapp::Metrics>( new xapp::Metrics( m, source ) );
+}
+
+std::unique_ptr<xapp::Metrics> xapp::Messenger::Alloc_metrics( std::string reporter, std::string source ) {
+       std::shared_ptr<Message> m;
+
+       m = Alloc_msg( 4096 );
+       return std::unique_ptr<xapp::Metrics>( new xapp::Metrics( m, reporter, source ) );
+}
+
 // ------------------- listening support -----------------------------------------------
 
 /*
index 173426c..82d8a49 100644 (file)
@@ -41,6 +41,7 @@
 
 #include "message.hpp"
 #include "alarm.hpp"
+#include "metrics.hpp"
 
 #ifndef RMR_FALSE
        #define RMR_FALSE       0
@@ -82,6 +83,10 @@ class Messenger {
                std::unique_ptr<xapp::Alarm> Alloc_alarm( std::string meid );
                std::unique_ptr<xapp::Alarm> Alloc_alarm( int prob_id, std::string meid );
 
+               std::unique_ptr<xapp::Metrics> Alloc_metrics( );                                        // metrics allocation
+               std::unique_ptr<xapp::Metrics> Alloc_metrics( std::string source );
+               std::unique_ptr<xapp::Metrics> Alloc_metrics( std::string reporter, std::string source );
+
                void Listen( );                                                                                                 // lisen driver
                std::unique_ptr<Message> Receive( int timeout );                                // receive 1 message
                void Stop( );                                                                                                   // force to stop
diff --git a/src/metrics/CMakeLists.txt b/src/metrics/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7930533
--- /dev/null
@@ -0,0 +1,40 @@
+# vim: sw=4 ts=4 noet:
+#
+#==================================================================================
+#   Copyright (c) 2020 Nokia
+#   Copyright (c) 2020 AT&T Intellectual Property.
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+#==================================================================================
+#
+
+
+# For clarity: this generates object, not a lib as the CM command implies.
+#
+add_library( metrics_objects OBJECT
+       metrics.cpp
+)
+
+target_include_directories (metrics_objects PUBLIC
+       $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
+       $<INSTALL_INTERFACE:include>
+       PRIVATE src)
+
+# header files should go into .../include/xfcpp/
+if( DEV_PKG )
+       install( FILES
+               metrics.hpp
+               DESTINATION ${install_inc}
+       )
+endif()
+
diff --git a/src/metrics/metrics.cpp b/src/metrics/metrics.cpp
new file mode 100644 (file)
index 0000000..1c27355
--- /dev/null
@@ -0,0 +1,284 @@
+// vi: ts=4 sw=4 noet:
+/*
+==================================================================================
+       Copyright (c) 2020 Nokia
+       Copyright (c) 2020 AT&T Intellectual Property.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================================
+*/
+
+/*
+       Mnemonic:       metrics.cpp
+       Abstract:       Impementation of the metrics functions. (see metrics.hpp)
+
+
+               void Set_source( std::string new_source );
+               void Set_reporter( std::string new_reporter );
+               void Push_data( std::string key, double value );
+
+       Date:           20 July 2020
+       Author:         E. Scott Daniels
+*/
+
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <rmr/RIC_message_types.h>
+#ifndef RIC_METRICS
+       #define RIC_METRICS 120
+#endif
+
+#include <iostream>
+
+#include "msg_component.hpp"
+#include "message.hpp"
+#include "metrics.hpp"
+
+extern char* __progname;                       // runtime lib supplied since we don't get argv[0]
+
+
+
+namespace xapp {
+
+
+
+// ------ private ----------------------------------------------
+
+
+/*
+       Return the current time in milliseconds past the UNIX epoch.
+*/
+static long long now( void ) {
+       struct timespec ts;
+       long long       now = 0;
+
+       clock_gettime( CLOCK_REALTIME, &ts );
+       now = (ts.tv_sec * 1000000) + (ts.tv_nsec/1000000);     // convert nano to milli and bang onto seconds
+
+       return now;
+}
+
+
+/*
+       Build the payload that we'll send.
+       Accepts a pointer to the payload message component in the RMR message that we are
+       to fill in, along with the maxmimum length of the payload.  Returns the length of
+       the payload that was acutally used.
+
+       Currently, the munchkin expects:
+               {
+                       "reporter": "<string>",
+                       "generator" "<string>",
+                       "timestamp": double,
+                       "data": [
+                               {
+                                       "id": "<string>",
+                                       "type": "<string>",
+                                       "value": double
+                               },...
+                       ]
+               }
+*/
+int xapp::Metrics::build_payload( xapp::Msg_component payload, int max_len ) {
+       int used;                                                                                       // actual size of payload created
+       std::string generator;
+
+
+       if(  data.compare( "" ) == 0 ) {                                        // xAPP never pushed any data
+               return 0;                                                                               // don't build, just bail
+       }
+
+       generator = source.compare( "" ) == 0 ? reporter : source;
+
+       used = snprintf( (char *) payload.get(), max_len,
+                       "{  "
+                       "\"reporter\": \"%s\", "
+                       "\"generator\": \"%s\", "
+                       "\"timestamp\": %lld, "
+                       "\"data\": [ %s ] "
+                       " }",
+                       reporter.c_str(),
+                       generator.c_str(),
+                       now(),
+                       data.c_str()
+       );
+
+       return used;
+}
+
+
+// --------------- builders/operators  -------------------------------------
+
+/*
+       Create a new metrics "message" with a provided (empty) RMR message.
+*/
+xapp::Metrics::Metrics( std::shared_ptr<Message> msg ) :
+       msg( msg ),
+       reporter( __progname ),
+       source( "" ),
+       data( "" )
+{ /* empty body */ }
+
+/*
+       Build a metrics for a value source other than the calling xAPP
+*/
+xapp::Metrics::Metrics( std::shared_ptr<Message> msg, std::string msource ) :
+       msg( msg ),
+       reporter( __progname ),
+       source( msource ),
+       data( "" )
+{ /* empty body */ }
+
+/*
+       Build a metrics object that allows the xAPP to set it's reporter name
+       rather than assuming the programme name and the source.
+
+       The xAPP can pass "" as the msource if the intent is just to supply
+       an alternate programme name which is also the source.
+*/
+xapp::Metrics::Metrics( std::shared_ptr<Message> msg, std::string reporter, std::string msource ) :
+       msg( msg ),
+       reporter( reporter ),
+       source( msource ),
+       data( "" )
+{ /* empty body */ }
+
+// ------------------ copy and move support ---------------------------------
+
+/*
+       Copy builder.  Given a source object instance (soi), create a copy.
+       Creating a copy should be avoided as it can be SLOW!
+*/
+xapp::Metrics::Metrics( const Metrics& soi ) {
+       msg = soi.msg;
+       data = soi.data;
+       source = soi.source;
+       reporter = soi.reporter;
+}
+
+/*
+       Assignment operator. Simiolar to the copycat, but "this" object exists and
+       may have data that needs to be released prior to making a copy of the soi.
+*/
+Metrics& xapp::Metrics::operator=( const Metrics& soi ) {
+       if( this != &soi ) {                            // cannot do self assignment
+               // anything that must be freed from 'this' must be done here
+
+               msg = soi.msg;
+               data = soi.data;
+               source = soi.source;
+               reporter = soi.reporter;
+       }
+
+       return *this;
+}
+
+/*
+       Move builder.  Given a source object instance (soi), move the information from
+       the soi ensuring that the destriction of the soi doesn't trash things from
+       under us.
+*/
+xapp::Metrics::Metrics( Metrics&& soi ) {
+       msg = soi.msg;          // capture pointers and copy data before setting soruce things to nil
+       data = soi.data;
+       source = soi.source;
+       reporter = soi.reporter;
+
+       soi.msg = NULL;         // prevent closing of RMR stuff on soi destroy
+}
+
+/*
+       Move Assignment operator. Move the message data to the existing object
+       ensure the object reference is cleaned up, and ensuring that the source
+       object references are removed.
+*/
+Metrics& xapp::Metrics::operator=( Metrics&& soi ) {
+       if( this != &soi ) {                            // cannot do self assignment
+               // anything that needs to be freed/delted from 'this', must be done here
+
+               msg = soi.msg;                  // move pointers and values
+               data = soi.data;
+               source = soi.source;
+               reporter = soi.reporter;
+
+               soi.msg = NULL;                 // prevent bad things when source is destroyed
+       }
+
+       return *this;
+}
+
+/*
+       Destroyer.
+*/
+xapp::Metrics::~Metrics() {
+       msg = NULL;
+}
+
+
+// ---- setters -------------------------------------------------
+
+void xapp::Metrics::Set_source( std::string new_source ) {
+       source = new_source;
+}
+
+void xapp::Metrics::Set_reporter( std::string new_reporter ) {
+       reporter = new_reporter;
+}
+
+/*
+       Pushes the key/value pair onto the current data list.
+       This could be more efficent, but for now it is simple.
+*/
+void xapp::Metrics::Push_data( std::string key, double value ) {
+       char    wbuf[1024];
+       char*   sep = (char *) " ";
+
+       if( data.compare( "" ) != 0 ) {                 // first on the list, no need for preceeding comma
+               sep = (char *) ", ";
+       }
+
+       snprintf( wbuf, sizeof( wbuf ), "%s{ \"id\": \"%s\", \"value\": %.5f }", sep, key.c_str(), value );
+
+       data += std::string( wbuf );
+}
+
+// ------------------- getters ------------------------------------
+
+
+// ------- message sending ---------------------------------------
+
+/*
+       Send the message by building the payload and passing to RMR.
+       Returns the state of the send (true == good). If the xapp did not
+       push any data, no send is actually invoked, and true is reported.
+*/
+bool xapp::Metrics::Send( ) {
+       int             used = 0;                       // actual num bytes used in the payload
+       bool    state = true;
+
+       used = build_payload( msg->Get_payload(), msg->Get_available_size() - 1 );
+       if( used > 0 ) {
+               //fprintf( stderr, ">>>> sending payload: %s\n", (char *) msg->Get_payload().get() );
+               state = msg->Send_msg(  RIC_METRICS, RMR_VOID_SUBID, used+1, NULL );
+       }
+
+       data = "";                              // clear data after the send
+
+       return state;
+}
+
+
+
+} // namespace
diff --git a/src/metrics/metrics.hpp b/src/metrics/metrics.hpp
new file mode 100644 (file)
index 0000000..77f258c
--- /dev/null
@@ -0,0 +1,102 @@
+// vi: ts=4 sw=4 noet:
+/*
+==================================================================================
+       Copyright (c) 2020 Nokia
+       Copyright (c) 2020 AT&T Intellectual Property.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================================
+*/
+
+/*
+       Mnemonic:       metrics.hpp
+       Abstract:       Headers for the metrics class.
+                               This class provides a simple interface for an xAPP to compose and
+                               send metrics. The class allows the xAPP to name the metric and to
+                               provide one or more key/value pairs which are sent to the metrics
+                               gateway (munchkin) when Send() is invoked. The class hides the
+                               true message structure that the munchkin desires from the xAPP.
+
+                               The munchkin endpoint is assumed to be a routable target and thus
+                               normal RMR messages (with appropriate type) are sent.
+
+       Date:           20 July 2020
+       Author:         E. Scott Daniels
+*/
+
+#ifndef _XAPP_METRICS_HPP
+#define _XAPP_METRICS_HPP
+
+
+#include <iostream>
+#include <string>
+
+#include "msg_component.hpp"
+
+namespace xapp {
+
+// ------------------------------------------------------------------------
+
+/*
+This class is loosely tied to the json expected by the munchkin. See the munchkin
+documentation for explicit information, but this will help to understand a bit:
+       {
+               "reporter": "<string>",
+               "generator" "<string>",
+               "timestamp": double,
+               "data": [
+                       {
+                               "id": "<string>",
+                               "type": "<string>",
+                               "value": double
+                       },...
+               ]
+       }
+*/
+
+class Metrics {
+       private:
+               std::shared_ptr<Message> msg;           // message to send
+
+                                                                                       // data for the payload
+               std::string reporter;                           // this application as it's reporting the metrics
+               std::string source;                                     // source of the measurement if not the reporter
+               std::string     data;                                   // key/value/type tuples "pushed"  waiting for send
+
+
+               int build_payload( xapp::Msg_component payload, int payload_len );
+
+       public:
+
+               Metrics( std::shared_ptr<Message> msg );                                                                                // builders
+               Metrics( std::shared_ptr<Message> msg, std::string msource );                                   // allow xapp to supply metric source
+               Metrics( std::shared_ptr<Message> msg, std::string reporter, std::string msource ); // allow xapp to supply all
+
+               Metrics( const Metrics& soi );                                  // copy to newly created instance
+               Metrics& operator=( const Metrics& soi );               // copy operator
+               Metrics( Metrics&& soi );                                               // mover
+               Metrics& operator=( Metrics&& soi );                    // move operator
+               ~Metrics();                                                                             // destroyer
+
+
+               void Set_source( std::string new_source );
+               void Set_reporter( std::string new_reporter );
+               void Push_data( std::string key, double value );
+
+
+               bool Send( );
+};
+
+} // namespace
+
+#endif
index 691f365..b7c843b 100644 (file)
@@ -3,15 +3,19 @@ coverage_opts = -ftest-coverage -fprofile-arcs
 
 binaries = unit_test
 
-tests::        unit_test jhash_test
+tests::        unit_test jhash_test metrics_test
+
+include_list = -I ../src/metrics -I ../src/alarm -I ../src/messaging
 
 # RMR emulation
 rmr_em.o::     rmr_em.c
        cc -g rmr_em.c -c
 
+# include the emulated rmr stuff, but we still need the rmr lib for symtab things which we cannot hope to
+# emulate (and don't need to)
+#
 unit_test:: unit_test.cpp rmr_em.o
-       # do NOT link the xapp lib; we include all modules in the test programme
-       g++ -g $(coverage_opts) -I ../src/alarm -I ../src/messaging unit_test.cpp -o unit_test rmr_em.o  -lpthread
+       g++ -g $(coverage_opts) $(include_list) unit_test.cpp -o unit_test -L../.build -lricxfcpp rmr_em.o  -lrmr_si -lpthread
 
 # build a special jwrapper object with coverage settings
 jwrapper_test.o:: ../src/json/jwrapper.c ../src/json/jwrapper.h
@@ -21,6 +25,10 @@ jhash_test:: jwrapper_test.o jhash_test.cpp
        # do NOT link the xapp lib; we include all modules in the test programme
        g++ -g $(coverage_opts) -I ../src/json -I ../ext/jsmn jhash_test.cpp -o jhash_test jwrapper_test.o -lrmr_si -lpthread
 
+metrics_test:: metrics_test.cpp rmr_em.o
+       # do NOT link the xapp lib; we include all modules in the test programme
+       g++ -g $(coverage_opts) $(include_list) metrics_test.cpp -o metrics_test -L../.build -lricxfcpp rmr_em.o -l rmr_si -lpthread
+
 # prune gcov files generated by system include files
 clean::
        rm -f *.h.gcov *.c.gcov
diff --git a/test/metrics_test.cpp b/test/metrics_test.cpp
new file mode 100644 (file)
index 0000000..3b939e3
--- /dev/null
@@ -0,0 +1,109 @@
+// vim: ts=4 sw=4 noet :
+/*
+==================================================================================
+       Copyright (c) 2020 Nokia
+       Copyright (c) 2020 AT&T Intellectual Property.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================================
+*/
+
+/*
+       Mnemonic:       metric_test.cpp
+       Abstract:       This is the unit test driver for the metrics class.
+
+       Date:           20 July 2020
+       Author:         E. Scott Daniels
+*/
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include <string>
+#include <memory>
+
+#include "../src/messaging/callback.hpp"
+#include "../src/messaging/default_cb.hpp"
+#include "../src/messaging/message.hpp"
+#include "../src/messaging/messenger.hpp"
+#include "../src/messaging/msg_component.hpp"
+#include "../src/alarm/alarm.hpp"
+#include "../src/xapp/xapp.hpp"
+
+#include "../src/metrics/metrics.hpp"          // overtly pull the code under test to get coverage opts
+#include "../src/metrics/metrics.cpp"
+
+#include "ut_support.cpp"
+
+int main( int argc, char** argv ) {
+       int             errors = 0;
+       std::shared_ptr<Xapp> x;
+       std::shared_ptr<xapp::Metrics> m;
+
+       set_test_name( "jhash_test" );
+
+       x = std::shared_ptr<Xapp>( new Xapp( "4560", true ) );
+       if( x == NULL ) {
+               fprintf( stderr, "<FAIL> unable to allocate xapp object\n" );
+               announce_results( 1 );
+               return 1;
+       }
+
+       m = x->Alloc_metrics( );
+       m->Push_data( "barney_balance", 216.49 );
+       m->Push_data( "fred_balance", 760.88 );
+       m->Send( );
+
+       // ensure data is cleared after first send
+       m->Push_data( "barney_balance", 216.49 );
+       m->Push_data( "fred_balance", 760.88 );
+       m->Push_data( "wilma_balance", 1986.0430 );
+       m->Send();
+
+       m->Send();                              // shouldn't really send
+
+
+       // drive alternate builders
+       m = x->Alloc_metrics( "different-source" );
+       m->Push_data( "wilma_balance", 1986.0430 );
+       m->Send();
+
+       m = x->Alloc_metrics( "different-app", "different-source" );
+       m->Push_data( "wilma_balance", 1986.0430 );
+       m->Push_data( "pebbles_balance", 1982.0614 );
+       m->Send();
+
+
+       m->Set_reporter( "set-reporter" );
+       m->Set_source( "set-source" );
+
+
+       // drive move/copy adjunct functions
+
+       xapp::Metrics b = *m.get();                             // force the move/copy operator functions to trigger
+       xapp::Metrics c( NULL );                                // a useless metric without a message
+       xapp::Metrics f( NULL, "source" );              // a useless metric to drive direct construction
+       c = *m.get();                                                   // drive copy = operator
+
+       b = std::move( c );                                             // move = operator
+       xapp::Metrics d = std::move( b );                       // move constructor
+
+
+       // ---------------------------- end housekeeping ---------------------------
+       announce_results( errors );
+       return !!errors;
+}
index 56f40b8..3e3c5bc 100644 (file)
@@ -40,6 +40,7 @@
 #include "../src/messaging/messenger.hpp"
 #include "../src/messaging/msg_component.hpp"
 #include "../src/alarm/alarm.hpp"
+#include "../src/metrics/metrics.hpp"
 #include "../src/xapp/xapp.hpp"
 
 #include "../src/messaging/callback.cpp"
@@ -107,6 +108,19 @@ void killer( std::shared_ptr<Xapp> x ) {
        x->Halt();
 }
 
+/*
+       Drive the constructors so that we actually see the coverage
+       in the .gc* files.  The metrics tests will actually verify that
+       the various underlying functions work.
+*/
+static int metrics( std::shared_ptr<Xapp> x ) {
+       std::shared_ptr<xapp::Metrics> m;
+
+       m = x->Alloc_metrics( );                                                // basic construction
+       m = x->Alloc_metrics( "different-source" );              // drive alternate builders
+       m = x->Alloc_metrics( "different-app", "different-source" );
+}
+
 int main( int argc, char** argv ) {
        std::thread* tinfo;                                     // we'll start a thread that will shut things down after a few seconds
        std::unique_ptr<xapp::Message> msg;
@@ -321,12 +335,6 @@ int main( int argc, char** argv ) {
        a = x->Alloc_alarm( 13, "meid-abc" );
        errors += fail_if( a == NULL, "unable to allcoate an alarm with meid and  problem id" );
 
-
-    //#####:  210:xapp::Alarm::Alarm( const Alarm& soi ) {
-    //#####:  227:Alarm& xapp::Alarm::operator=( const Alarm& soi ) {
-    //#####:  249:xapp::Alarm::Alarm( Alarm&& soi ) {
-    //#####:  269:Alarm& xapp::Alarm::operator=( Alarm&& soi ) {
-
        a->Set_meid( "changed_meid" );
        for( i = 0; i < 6; i++ ) {
                a->Set_severity( i );                   // drive all switch possibilities
@@ -357,6 +365,12 @@ int main( int argc, char** argv ) {
        b = std::move( c );                                             // move = operator
        xapp::Alarm d = std::move( b );                 // move constructor
 
+
+       // ------ minimal metrics to prove coverage ------------------------------------------------------------
+       metrics( x );
+
+       // ------------------------------------------------------------------------------------------------------
+
        announce_results( errors );
        return errors > 0;
 }
index 2f30686..3e06a53 100755 (executable)
@@ -60,6 +60,16 @@ function abort_if_error {
 
 spew="cat"                                     # default to dumping all make output on failure (-q turns it to ~40 lines)
 
+if [[ -d ../.build ]]
+then
+       build_dir="../.build"
+else
+       if [[ -d ../build ]]
+       then
+               build_dir="../build"
+       fi
+fi
+
 while [[ $1 == "-"* ]]
 do
        case $1 in
@@ -70,8 +80,24 @@ do
        shift
 done
 
-export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
-export LIBRARY_PATH=/usr/local/lib:$LIBRARY_PATH
+while [[ $1 == *"="* ]]
+do
+       case ${1%%=*} in
+               CMBUILD)
+                       export build_dir=${1##*=}
+                       ;;
+       esac
+
+       shift
+done
+
+echo "## INFO ##"
+echo "build dir=$build_dir"
+find $build_dir -name "libricxfcpp.*"
+echo "## INFO ##"
+
+export LD_LIBRARY_PATH=$build_dir:/usr/local/lib:$LD_LIBRARY_PATH
+export LIBRARY_PATH=$build_dir:/usr/local/lib:$LIBRARY_PATH
 
 make nuke >/dev/null
 make tests >/tmp/PID$$.log 2>&1
@@ -80,7 +106,7 @@ echo "tests successfully built" >&2
 
 spew="cat"
 
-for x in unit_test jhash_test
+for x in unit_test jhash_test metrics_test
 do
        ./$x >/tmp/PID$$.log 2>&1
        abort_if_error $? "test failed: $x"