Skip to content

Commit a4683a1

Browse files
committed
HPCC-33338 Convert statically allocated metrics to dynamic allocation
Removed statically allocated metrics in favor of using MODULE_INIT Signed-Off-By: Kenneth Rowland kenneth.rowland@lexisnexisrisk.com
1 parent 5b9ce6b commit a4683a1

File tree

5 files changed

+113
-38
lines changed

5 files changed

+113
-38
lines changed

dali/base/danqs.cpp

+6-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,12 @@
3333
#pragma warning (disable : 4355)
3434
#endif
3535

36-
static auto pNqRequestsCount = hpccMetrics::registerCounterMetric("dali.nq.requests.received", "The total number of Dali NQ requests received", SMeasureCount);
36+
static std::shared_ptr<hpccMetrics::CounterMetric> pNqRequestsCount;
37+
MODULE_INIT(INIT_PRIORITY_STANDARD)
38+
{
39+
pNqRequestsCount = hpccMetrics::registerCounterMetric("dali.nq.requests.received", "The total number of Dali NQ requests received", SMeasureCount);
40+
return true;
41+
}
3742

3843
enum MQueueRequestKind {
3944
MQR_ADD_QUEUE,

dali/base/dasds.cpp

+14-4
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,20 @@ static unsigned readWriteTimeout = 60000;
8484
#define DEFAULT_LCIDLE_RATE 1 // 1 write transactions per idle period. <= this rate is deemed idle (suitable for save)
8585
#define STORENOTSAVE_WARNING_PERIOD 72 // hours
8686

87-
static auto pSdsRequestsReceived = hpccMetrics::registerCounterMetric("dali.sds.requests.received", "The total number of Dali SDS requests received", SMeasureCount);
88-
static auto pSdsRequestsStarted = hpccMetrics::registerCounterMetric("dali.sds.requests.started", "The total number of Dali SDS requests started", SMeasureCount);
89-
static auto pSdsRequestsCompleted = hpccMetrics::registerCounterMetric("dali.sds.requests.completed", "The total number of Dali SDS requests completed", SMeasureCount);
90-
static auto pSdsRequestsPending = hpccMetrics::registerGaugeFromCountersMetric("dali.sds.requests.pending", "Current number of pending SDS requests", SMeasureCount, pSdsRequestsReceived, pSdsRequestsStarted);
87+
static std::shared_ptr<hpccMetrics::CounterMetric> pSdsRequestsReceived;
88+
static std::shared_ptr<hpccMetrics::CounterMetric> pSdsRequestsStarted;
89+
static std::shared_ptr<hpccMetrics::CounterMetric> pSdsRequestsCompleted;
90+
static std::shared_ptr<hpccMetrics::GaugeMetricFromCounters> pSdsRequestsPending;
91+
92+
MODULE_INIT(INIT_PRIORITY_STANDARD)
93+
{
94+
pSdsRequestsReceived = hpccMetrics::registerCounterMetric("dali.sds.requests.received", "The total number of Dali SDS requests received", SMeasureCount);
95+
pSdsRequestsStarted = hpccMetrics::registerCounterMetric("dali.sds.requests.started", "The total number of Dali SDS requests started", SMeasureCount);
96+
pSdsRequestsCompleted = hpccMetrics::registerCounterMetric("dali.sds.requests.completed", "The total number of Dali SDS requests completed", SMeasureCount);
97+
pSdsRequestsPending = hpccMetrics::registerGaugeFromCountersMetric("dali.sds.requests.pending", "Current number of pending SDS requests", SMeasureCount, pSdsRequestsReceived, pSdsRequestsStarted);
98+
return true;
99+
}
100+
91101

92102
// #define TEST_NOTIFY_HANDLER
93103

devdoc/Metrics.md

+78-26
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,7 @@ add jlib as a dependent lib (if not already doing so).
481481
482482
The general steps for instrumentation are
483483
484-
1. Determine what component state is to be measured. This requires deep knowledge of the
484+
1. Determine what component state to measure. This requires deep knowledge of the
485485
component.
486486
2. Create metric objects for each measured state and add each to the manager.
487487
3. Add updates for each metric throughout the component to track state
@@ -490,8 +490,8 @@ The general steps for instrumentation are
490490
The component may retrieve the metrics manager singleton object and manually create
491491
and add metrics. To simplify the process of metric creation (2 above), the framework
492492
provides a set of register functions for each metric. Each creates a metric, registers
493-
it, and returns a shared pointer to the metric (see below).Use of the register functions
494-
is the recommended approach and alleviates the component from needing to get a reference
493+
it, and returns a shared pointer to the metric (see below). Use of the register functions
494+
is the recommended approach and alleviates the component from needing a reference
495495
to the manager.
496496
497497
If the component desires to get a reference to the metrics manager singleton, the following
@@ -515,50 +515,102 @@ The following is an example of creating and registering a counter metric.
515515
std::shared_ptr<CounterMetric> pCounter = registerCounterMetric("metric.name", "description");
516516
```
517517

518-
Metrics can be created in one of two ways: statically or centrally. Static creation should
519-
ONLY be reserved for cases where the component does not have some central place where all metrics
520-
can be created. The primary reason to avoid static creation is that it if there is a problem
521-
during creation, any log messages emitted are lost. Debugging is more difficult in this case.
518+
### Metric Creation
519+
The method by which a component creates a metric depends on component implementation. The sections
520+
that follow provide guidance on different methods of metric creation. Choose the method that
521+
best matches component implementation.
522522

523-
Central creation is the recommended approach. This is where all metrics are created in a single
524-
place, such as the component's constructor. This allows for all metrics to be created at once. If
525-
there is a problem during creation, any emitted log messages are not lost.
523+
Metrics are guaranteed to always be created. Problems only arise when registering. If there is a
524+
failure during registration, the metric can still be used withing the component to update state.
525+
However, the metric will not be reported during collection.
526526

527-
In some cases, a component may be created and destroyed multiple times. An example is a protocol
528-
handler. For these cases a blend of static and central creation is recommended. The code below
529-
details how:
527+
#### During Module Initialization
528+
If the component is a shared library whose code is not also shared with a main application,
529+
then the component should create metrics during module initialization. The following code shows how
530+
to register a metric during module initialization:
530531

531532
```cpp
532-
static std::once_flag metricsInitialized;
533-
static std::shared_ptr<hpccMetrics::CounterMetric> pCount1;
534-
... others as needed
533+
static std::shared_ptr<hpccMetrics::CounterMetric> pCount;
534+
535+
MODULE_INIT(INIT_PRIORITY_STANDARD)
536+
{
537+
pCount1 = hpccMetrics::registerCounterMetric("name", "description", SMeasureCount);
538+
return true;
539+
}
540+
541+
MODULE_EXIT()
542+
{
543+
pCount1 = nullptr; // note this is optional
544+
}
545+
```
546+
547+
Note that the metric is not required to be a static variable. Other options include:
548+
* A global variable
549+
* A static class member variable
550+
551+
#### During Construction
552+
If the metric is based on measuring state in a class that is created and destroyed multiple times,
553+
then the metric should be a static variable in the class. The metric is created during the first
554+
construction and then reused for subsequent constructions. The metric is destroyed when the class
555+
static variables are destroyed. The following code shows how to register a metric once:
556+
557+
```cpp
558+
559+
//
560+
// Allocate the class static variables
561+
static std::once_flag ClassX::metricsInitialized;
562+
static std::shared_ptr<hpccMetrics::CounterMetric> ClassX::pCount1;
563+
564+
class ClassX
565+
{
566+
public:
567+
ClassX();
568+
void method1();
569+
570+
private:
571+
static std::shared_ptr<hpccMetrics::CounterMetric> pCount1;
572+
static std::once_flag metricsInitialized;
573+
}
535574
536575
ClassX::ClassX()
537576
{
538577
std::call_once(metricsInitialized, []()
539578
{
540-
pCount1 = registerCounterMetric("metric1", "description");
541-
... others as needed
542-
});
579+
pCount1 = hpccMetrics::registerCounterMetric("metric1", "description");
580+
});
543581
}
544582
545583
void ClassX::method1()
546584
{
547-
pCount1->inc(1); // example of (3 above)
585+
pCount1->inc(1); // Update state
548586
}
549587
550588
```
551589

552-
The code above uses a static _once_flag_ and a _call_once_ block to ensure that the metrics are
590+
The static _once_flag_ and _call_once_ block ensure that the metric is
553591
only created once. The first time the constructor is called, the lambda is executed. Subsequent
554592
calls to the constructor do not execute the lambda. The static shared\_ptr for each metric maintain
555593
references to each metric making them available throughout the class.
556594

557-
Invalid metrics are always created, but not registered. This allows component code to continue
558-
taking measurements, update state, and count events with a valid metric. However, no results
559-
will be reported. Essentially, the metric is a black hole.
595+
#### Static Creation
596+
Static creation should be a last resort. If the above methods do not solve the problem of metric
597+
allocation and registering, then static creation is the next best choice. The primary reason to
598+
avoid static creation is that if there is a problem during creation, any log messages
599+
or exceptions are lost. Debugging is more difficult in this case.
600+
601+
An example of static creation is shown below:
602+
603+
```cpp
604+
605+
//
606+
// Allocate the class static variables
607+
static std::shared_ptr<hpccMetrics::CounterMetric> pCount1 = hpccMetrics::registerCounterMetric("metric1", "description");
608+
609+
```
610+
611+
### Metric State Updates
560612

561-
Note in the example above, only a single line of code is needed to update state. This is true for
613+
Note in the examples above, only a single line of code is needed to update state. This is true for
562614
all metric types.
563615

564616
That's it! There are no component requirements related to collection or
@@ -569,7 +621,7 @@ sinks.
569621
If your component is already tracking a metric, you may not need to convert it to
570622
a defined framework metric type. Instead, you can create a custom metric and
571623
pass a reference to the existing metric value. The metric value, however, must be
572-
a scalar value that can be converted to a 64bit unsigned integer (\_\_uint64).
624+
a scalar value that can cast to a 64bit unsigned integer (\_\_uint64).
573625

574626
The following is an example of creating a custom metric (you must provide the metric type):
575627

esp/platform/espprotocol.cpp

+9-6
Original file line numberDiff line numberDiff line change
@@ -27,26 +27,29 @@
2727
#endif
2828
#include "jmetrics.hpp"
2929

30-
static RelaxedAtomic<unsigned> gActiveRequests;
30+
static std::shared_ptr<hpccMetrics::GaugeMetric> pActiveRequests;
3131

32-
static auto pActiveRequests = hpccMetrics::registerCustomMetric("esp.requests.active", "Number of active requests",
33-
hpccMetrics::METRICS_GAUGE, gActiveRequests, SMeasureCount);
32+
MODULE_INIT(INIT_PRIORITY_STANDARD)
33+
{
34+
pActiveRequests = hpccMetrics::registerGaugeMetric("esp.requests.active", "Number of active requests", SMeasureCount);
35+
return true;
36+
}
3437

3538
typedef IXslProcessor * (*getXslProcessor_func)();
3639

3740
unsigned ActiveRequests::getCount()
3841
{
39-
return gActiveRequests;
42+
return pActiveRequests->queryValue();
4043
}
4144

4245
ActiveRequests::ActiveRequests()
4346
{
44-
gActiveRequests++;
47+
pActiveRequests->adjust(1);
4548
}
4649

4750
ActiveRequests::~ActiveRequests()
4851
{
49-
gActiveRequests--;
52+
pActiveRequests->adjust(-1);
5053
}
5154

5255
CEspApplicationPort::CEspApplicationPort(bool viewcfg, CEspProtocol* prot) : viewConfig(viewcfg), rootAuth(false), navResize(false), navScroll(false), navWidth(165), protocol(prot)

esp/platform/txsummary.cpp

+6-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,12 @@
2424

2525
#define MATCH_ENTRY [&](const EntryValue& e) {return strieq(e.get()->name, pathPart);}
2626

27-
static auto pRequestCount = hpccMetrics::registerCounterMetric("esp.requests.received", "Number of requests received", SMeasureCount);
27+
static std::shared_ptr<hpccMetrics::CounterMetric> pRequestCount;
28+
MODULE_INIT(INIT_PRIORITY_STANDARD)
29+
{
30+
pRequestCount = hpccMetrics::registerCounterMetric("esp.requests.received", "Number of requests received", SMeasureCount);
31+
return true;
32+
}
2833

2934
inline bool validate(const char* k)
3035
{

0 commit comments

Comments
 (0)