[Metrics SDK] Cleanup of old _metric api/sdk (#1734)

This commit is contained in:
Ehsan Saei 2022-11-06 19:31:37 +01:00 committed by GitHub
parent 99a9b4cc07
commit ec8895bc98
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
67 changed files with 1 additions and 12311 deletions

View File

@ -1,88 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef ENABLE_METRICS_PREVIEW
# include "opentelemetry/_metrics/instrument.h"
# include "opentelemetry/_metrics/observer_result.h"
OPENTELEMETRY_BEGIN_NAMESPACE
namespace metrics
{
template <class T>
class ValueObserver : virtual public AsynchronousInstrument<T>
{
public:
ValueObserver() = default;
ValueObserver(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
bool enabled,
void (*callback)(ObserverResult<T>))
{}
/*
* Updates the instruments aggregator with the new value. The labels should
* contain the keys and values to be associated with this value.
*
* @param value is the numerical representation of the metric being captured
* @param labels the set of labels, as key-value pairs
*/
virtual void observe(T value, const common::KeyValueIterable &labels) override = 0;
/**
* Captures data by activating the callback function associated with the
* instrument and storing its return value. Callbacks for asynchronous
* instruments are defined during construction.
*
* @param none
* @return none
*/
virtual void run() override = 0;
};
template <class T>
class SumObserver : virtual public AsynchronousInstrument<T>
{
public:
SumObserver() = default;
SumObserver(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
bool enabled,
void (*callback)(ObserverResult<T>))
{}
virtual void observe(T value, const common::KeyValueIterable &labels) override = 0;
virtual void run() override = 0;
};
template <class T>
class UpDownSumObserver : virtual public AsynchronousInstrument<T>
{
public:
UpDownSumObserver() = default;
UpDownSumObserver(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
bool enabled,
void (*callback)(ObserverResult<T>))
{}
virtual void observe(T value, const common::KeyValueIterable &labels) override = 0;
virtual void run() override = 0;
};
} // namespace metrics
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,209 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef ENABLE_METRICS_PREVIEW
# include <iostream>
# include "opentelemetry/common/attribute_value.h"
# include "opentelemetry/common/key_value_iterable_view.h"
# include "opentelemetry/nostd/shared_ptr.h"
# include "opentelemetry/nostd/string_view.h"
OPENTELEMETRY_BEGIN_NAMESPACE
namespace metrics
{
// Enum classes to help determine instrument types in other parts of the API
enum class InstrumentKind
{
Counter = 0,
UpDownCounter = 1,
ValueRecorder = 2,
ValueObserver = 3,
SumObserver = 4,
UpDownSumObserver = 5,
};
class Instrument
{
public:
// Note that Instruments should be created using the Meter class.
// Please refer to meter.h for documentation.
Instrument() = default;
/**
* Base class constructor for all other instrument types. Whether or not
* an instrument is synchronous or bound, it requires a name, description,
* unit, and enabled flag.
*
* @param name is the identifier of the instrumenting library
* @param description explains what the metric captures
* @param unit specifies the data type held in the instrument
* @param enabled determines if the metric is currently capturing data
* @return Instrument type with the specified attributes
*/
Instrument(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
bool enabled)
{}
// Returns true if the instrument is enabled and collecting data
virtual bool IsEnabled() = 0;
// Return the instrument name
virtual nostd::string_view GetName() = 0;
// Return the instrument description
virtual nostd::string_view GetDescription() = 0;
// Return the insrument's units of measurement
virtual nostd::string_view GetUnits() = 0;
// Return the intrument's kind
virtual InstrumentKind GetKind() = 0;
virtual ~Instrument() = default;
};
template <class T>
class BoundSynchronousInstrument : virtual public Instrument
{
public:
BoundSynchronousInstrument() = default;
BoundSynchronousInstrument(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
bool enabled);
/**
* Frees the resources associated with this Bound Instrument.
* The Metric from which this instrument was created is not impacted.
*
* @param none
* @return void
*/
virtual void unbind() {}
/**
* Incremements the reference count of this bound object when a new instance is
* either created or the same instance is returned as a result of binding
*
* @param none
* @return void
*/
virtual void inc_ref() {}
/**
* Return the object's current reference count. This information is used to remove
* stale objects from instrument registries.
*/
virtual int get_ref() { return 0; }
/**
* Records a single synchronous metric event; a call to the aggregator
* Since this is a bound synchronous instrument, labels are not required in * metric capture
* calls.
*
* @param value is the numerical representation of the metric being captured
* @return void
*/
virtual void update(T value) {}
};
template <class T>
class SynchronousInstrument : virtual public Instrument
{
public:
SynchronousInstrument() = default;
SynchronousInstrument(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
bool enabled)
{}
/**
* Returns a Bound Instrument associated with the specified labels. * Multiples requests
* with the same set of labels may return the same Bound Instrument instance.
*
* It is recommended that callers keep a reference to the Bound Instrument
* instead of repeatedly calling this operation.
*
* @param labels the set of labels, as key-value pairs
* @return a Bound Instrument
*/
virtual nostd::shared_ptr<BoundSynchronousInstrument<T>> bind(
const common::KeyValueIterable &labels)
{
return nostd::shared_ptr<BoundSynchronousInstrument<T>>();
}
/**
* Records a single synchronous metric event.
* Since this is an unbound synchronous instrument, labels are required in * metric capture
* calls.
*
* update can be used in instruments with both add or record since it simply
* activated the aggregator
*
* @param labels the set of labels, as key-value pairs
* @param value is the numerical representation of the metric being captured
* @return void
*/
virtual void update(T value, const common::KeyValueIterable &labels) = 0;
};
template <class T>
class ObserverResult;
template <class T>
class AsynchronousInstrument : virtual public Instrument
{
public:
AsynchronousInstrument() = default;
AsynchronousInstrument(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
bool enabled,
void(callback)(ObserverResult<T>))
{}
/**
* Captures data through a manual call rather than the automatic collection process instituted
* in the run function. Asynchronous instruments are generally expected to obtain data from
* their callbacks rather than direct calls. This function is used by the callback to store data.
*
* @param value is the numerical representation of the metric being captured
* @param labels is the numerical representation of the metric being captured
* @return none
*/
virtual void observe(T value, const common::KeyValueIterable &labels) = 0;
/**
* Captures data by activating the callback function associated with the
* instrument and storing its return value. Callbacks for asynchronous
* instruments are defined during construction.
*
* @param none
* @return none
*/
virtual void run() = 0;
protected:
// Callback function which takes a pointer to an Asynchronous instrument (this) type which is
// stored in an observer result type and returns nothing. This function calls the instrument's
// observe.
void (*callback_)(ObserverResult<T>);
};
} // namespace metrics
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,288 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef ENABLE_METRICS_PREVIEW
# include "opentelemetry/_metrics/async_instruments.h"
# include "opentelemetry/_metrics/instrument.h"
# include "opentelemetry/_metrics/sync_instruments.h"
# include "opentelemetry/nostd/shared_ptr.h"
# include "opentelemetry/nostd/span.h"
# include "opentelemetry/nostd/string_view.h"
# include "opentelemetry/version.h"
OPENTELEMETRY_BEGIN_NAMESPACE
namespace metrics
{
/**
* Handles instrument creation and provides a facility for batch recording.
*
* This class provides methods to create new metric instruments, record a
* batch of values to a specified set of instruments, and collect
* measurements from all instruments.
*
*/
class Meter
{
public:
virtual ~Meter() = default;
/**
* Creates a Counter with the passed characteristics and returns a shared_ptr to that Counter.
*
* @param name the name of the new Counter.
* @param description a brief description of what the Counter is used for.
* @param unit the unit of metric values following https://unitsofmeasure.org/ucum.html.
* @param enabled a boolean value that turns on or off the metric instrument.
* @return a shared pointer to the created Counter.
* @throws NullPointerException if {@code name} is null
* @throws IllegalArgumentException if a different metric by the same name exists in this meter.
* @throws IllegalArgumentException if the {@code name} does not match spec requirements.
*/
virtual nostd::shared_ptr<Counter<short>> NewShortCounter(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) = 0;
virtual nostd::shared_ptr<Counter<int>> NewIntCounter(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) = 0;
virtual nostd::shared_ptr<Counter<float>> NewFloatCounter(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) = 0;
virtual nostd::shared_ptr<Counter<double>> NewDoubleCounter(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) = 0;
/**
* Creates an UpDownCounter with the passed characteristics and returns a shared_ptr to that
* UpDownCounter.
*
* @param name the name of the new UpDownCounter.
* @param description a brief description of what the UpDownCounter is used for.
* @param unit the unit of metric values following https://unitsofmeasure.org/ucum.html.
* @param enabled a boolean value that turns on or off the metric instrument.
* @return a shared pointer to the created UpDownCounter.
* @throws NullPointerException if {@code name} is null
* @throws IllegalArgumentException if a different metric by the same name exists in this meter.
* @throws IllegalArgumentException if the {@code name} does not match spec requirements.
*/
virtual nostd::shared_ptr<UpDownCounter<short>> NewShortUpDownCounter(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) = 0;
virtual nostd::shared_ptr<UpDownCounter<int>> NewIntUpDownCounter(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) = 0;
virtual nostd::shared_ptr<UpDownCounter<float>> NewFloatUpDownCounter(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) = 0;
virtual nostd::shared_ptr<UpDownCounter<double>> NewDoubleUpDownCounter(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) = 0;
/**
* Creates a ValueRecorder with the passed characteristics and returns a shared_ptr to that
* ValueRecorder.
*
* @param name the name of the new ValueRecorder.
* @param description a brief description of what the ValueRecorder is used for.
* @param unit the unit of metric values following https://unitsofmeasure.org/ucum.html.
* @param enabled a boolean value that turns on or off the metric instrument.
* @return a shared pointer to the created DoubleValueRecorder.
* @throws NullPointerException if {@code name} is null
* @throws IllegalArgumentException if a different metric by the same name exists in this meter.
* @throws IllegalArgumentException if the {@code name} does not match spec requirements.
*/
virtual nostd::shared_ptr<ValueRecorder<short>> NewShortValueRecorder(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) = 0;
virtual nostd::shared_ptr<ValueRecorder<int>> NewIntValueRecorder(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) = 0;
virtual nostd::shared_ptr<ValueRecorder<float>> NewFloatValueRecorder(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) = 0;
virtual nostd::shared_ptr<ValueRecorder<double>> NewDoubleValueRecorder(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) = 0;
/**
* Creates a SumObserver with the passed characteristics and returns a shared_ptr to that
* SumObserver.
*
* @param name the name of the new SumObserver.
* @param description a brief description of what the SumObserver is used for.
* @param unit the unit of metric values following https://unitsofmeasure.org/ucum.html.
* @param enabled a boolean value that turns on or off the metric instrument.
* @param callback the function to be observed by the instrument.
* @return a shared pointer to the created SumObserver.
* @throws NullPointerException if {@code name} is null
* @throws IllegalArgumentException if a different metric by the same name exists in this meter.
* @throws IllegalArgumentException if the {@code name} does not match spec requirements.
*/
virtual nostd::shared_ptr<SumObserver<short>> NewShortSumObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(ObserverResult<short>)) = 0;
virtual nostd::shared_ptr<SumObserver<int>> NewIntSumObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(ObserverResult<int>)) = 0;
virtual nostd::shared_ptr<SumObserver<float>> NewFloatSumObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(ObserverResult<float>)) = 0;
virtual nostd::shared_ptr<SumObserver<double>> NewDoubleSumObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(ObserverResult<double>)) = 0;
/**
* Creates an UpDownSumObserver with the passed characteristics and returns a shared_ptr to
* that UpDowNSumObserver.
*
* @param name the name of the new UpDownSumObserver.
* @param description a brief description of what the UpDownSumObserver is used for.
* @param unit the unit of metric values following https://unitsofmeasure.org/ucum.html.
* @param enabled a boolean value that turns on or off the metric instrument.
* @param callback the function to be observed by the instrument.
* @return a shared pointer to the created UpDownSumObserver.
* @throws NullPointerException if {@code name} is null
* @throws IllegalArgumentException if a different metric by the same name exists in this meter.
* @throws IllegalArgumentException if the {@code name} does not match spec requirements.
*/
virtual nostd::shared_ptr<UpDownSumObserver<short>> NewShortUpDownSumObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(ObserverResult<short>)) = 0;
virtual nostd::shared_ptr<UpDownSumObserver<int>> NewIntUpDownSumObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(ObserverResult<int>)) = 0;
virtual nostd::shared_ptr<UpDownSumObserver<float>> NewFloatUpDownSumObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(ObserverResult<float>)) = 0;
virtual nostd::shared_ptr<UpDownSumObserver<double>> NewDoubleUpDownSumObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(ObserverResult<double>)) = 0;
/**
* Creates a ValueObserver with the passed characteristics and returns a shared_ptr to that
* ValueObserver.
*
* @param name the name of the new ValueObserver.
* @param description a brief description of what the ValueObserver is used for.
* @param unit the unit of metric values following https://unitsofmeasure.org/ucum.html.
* @param enabled a boolean value that turns on or off the metric instrument.
* @param callback the function to be observed by the instrument.
* @return a shared pointer to the created ValueObserver.
* @throws NullPointerException if {@code name} is null
* @throws IllegalArgumentException if a different metric by the same name exists in this meter.
* @throws IllegalArgumentException if the {@code name} does not match spec requirements.
*/
virtual nostd::shared_ptr<ValueObserver<short>> NewShortValueObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(ObserverResult<short>)) = 0;
virtual nostd::shared_ptr<ValueObserver<int>> NewIntValueObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(ObserverResult<int>)) = 0;
virtual nostd::shared_ptr<ValueObserver<float>> NewFloatValueObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(ObserverResult<float>)) = 0;
virtual nostd::shared_ptr<ValueObserver<double>> NewDoubleValueObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(ObserverResult<double>)) = 0;
/**
* Utility method that allows users to atomically record measurements to a set of
* synchronous metric instruments with a common set of labels.
*
* @param labels the set of labels to associate with this recorder.
* @param instruments a span of pointers to the instruments to record to.
* @param values a span of values to record to the instruments in the corresponding
* position in the instruments span.
*/
virtual void RecordShortBatch(const common::KeyValueIterable &labels,
nostd::span<SynchronousInstrument<short> *> instruments,
nostd::span<const short> values) noexcept = 0;
virtual void RecordIntBatch(const common::KeyValueIterable &labels,
nostd::span<SynchronousInstrument<int> *> instruments,
nostd::span<const int> values) noexcept = 0;
virtual void RecordFloatBatch(const common::KeyValueIterable &labels,
nostd::span<SynchronousInstrument<float> *> instruments,
nostd::span<const float> values) noexcept = 0;
virtual void RecordDoubleBatch(const common::KeyValueIterable &labels,
nostd::span<SynchronousInstrument<double> *> instruments,
nostd::span<const double> values) noexcept = 0;
};
} // namespace metrics
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,32 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef ENABLE_METRICS_PREVIEW
# include "opentelemetry/_metrics/meter.h"
# include "opentelemetry/nostd/shared_ptr.h"
# include "opentelemetry/nostd/string_view.h"
OPENTELEMETRY_BEGIN_NAMESPACE
namespace metrics
{
/**
* Creates new Meter instances.
*/
class MeterProvider
{
public:
virtual ~MeterProvider() = default;
/**
* Gets or creates a named Meter instance.
*
* Optionally a version can be passed to create a named and versioned Meter
* instance.
*/
virtual nostd::shared_ptr<Meter> GetMeter(nostd::string_view library_name,
nostd::string_view library_version = "") = 0;
};
} // namespace metrics
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,654 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef ENABLE_METRICS_PREVIEW
// Please refer to provider.h for documentation on how to obtain a Meter object.
//
// This file is part of the internal implementation of OpenTelemetry. Nothing in this file should be
// used directly. Please refer to meter.h for documentation on these interfaces.
# include "opentelemetry/_metrics/async_instruments.h"
# include "opentelemetry/_metrics/instrument.h"
# include "opentelemetry/_metrics/meter.h"
# include "opentelemetry/_metrics/meter_provider.h"
# include "opentelemetry/_metrics/sync_instruments.h"
# include "opentelemetry/nostd/string_view.h"
# include "opentelemetry/nostd/unique_ptr.h"
# include "opentelemetry/version.h"
# include <memory>
// TODO: Create generic short pattern for opentelemetry::common and opentelemetry::trace and others
// as necessary
OPENTELEMETRY_BEGIN_NAMESPACE
namespace metrics
{
template <class T>
class NoopValueObserver : public ValueObserver<T>
{
public:
NoopValueObserver(nostd::string_view /*name*/,
nostd::string_view /*description*/,
nostd::string_view /*unit*/,
bool /*enabled*/,
void (*callback)(ObserverResult<T>))
{}
virtual bool IsEnabled() override { return false; }
virtual nostd::string_view GetName() override { return nostd::string_view(""); }
virtual nostd::string_view GetDescription() override { return nostd::string_view(""); }
virtual nostd::string_view GetUnits() override { return nostd::string_view(""); }
virtual void observe(T value, const common::KeyValueIterable &labels) override {}
virtual void run() override {}
virtual InstrumentKind GetKind() override { return InstrumentKind::Counter; }
};
template <class T>
class NoopSumObserver : public SumObserver<T>
{
public:
NoopSumObserver(nostd::string_view /*name*/,
nostd::string_view /*description*/,
nostd::string_view /*unit*/,
bool /*enabled*/,
void (*callback)(ObserverResult<T>))
{}
virtual bool IsEnabled() override { return false; }
virtual nostd::string_view GetName() override { return nostd::string_view(""); }
virtual nostd::string_view GetDescription() override { return nostd::string_view(""); }
virtual nostd::string_view GetUnits() override { return nostd::string_view(""); }
virtual void observe(T value, const common::KeyValueIterable &labels) override {}
virtual void run() override {}
virtual InstrumentKind GetKind() override { return InstrumentKind::Counter; }
};
template <class T>
class NoopUpDownSumObserver : public UpDownSumObserver<T>
{
public:
NoopUpDownSumObserver(nostd::string_view /*name*/,
nostd::string_view /*description*/,
nostd::string_view /*unit*/,
bool /*enabled*/,
void (*callback)(ObserverResult<T>))
{}
virtual bool IsEnabled() override { return false; }
virtual nostd::string_view GetName() override { return nostd::string_view(""); }
virtual nostd::string_view GetDescription() override { return nostd::string_view(""); }
virtual nostd::string_view GetUnits() override { return nostd::string_view(""); }
virtual void observe(T value, const common::KeyValueIterable &labels) override {}
virtual void run() override {}
virtual InstrumentKind GetKind() override { return InstrumentKind::Counter; }
};
template <class T>
class BoundNoopCounter : public BoundCounter<T>
{
public:
BoundNoopCounter() = default;
BoundNoopCounter(nostd::string_view /*name*/,
nostd::string_view /*description*/,
nostd::string_view /*unit*/,
bool /*enabled*/)
{}
virtual void add(T value) override {}
virtual bool IsEnabled() override { return false; }
virtual nostd::string_view GetName() override { return nostd::string_view(""); }
virtual nostd::string_view GetDescription() override { return nostd::string_view(""); }
virtual nostd::string_view GetUnits() override { return nostd::string_view(""); }
virtual InstrumentKind GetKind() override { return InstrumentKind::Counter; }
};
template <class T>
class NoopCounter : public Counter<T>
{
public:
NoopCounter() = default;
NoopCounter(nostd::string_view /*name*/,
nostd::string_view /*description*/,
nostd::string_view /*unit*/,
bool /*enabled*/)
{}
nostd::shared_ptr<BoundNoopCounter<T>> bindNoopCounter(
const common::KeyValueIterable & /*labels*/)
{
return nostd::shared_ptr<BoundNoopCounter<T>>(new BoundNoopCounter<T>());
}
virtual void add(T value, const common::KeyValueIterable & /*labels*/) override {}
virtual void update(T value, const common::KeyValueIterable & /*labels*/) override {}
virtual bool IsEnabled() override { return false; }
virtual nostd::string_view GetName() override { return nostd::string_view(""); }
virtual nostd::string_view GetDescription() override { return nostd::string_view(""); }
virtual nostd::string_view GetUnits() override { return nostd::string_view(""); }
virtual InstrumentKind GetKind() override { return InstrumentKind::Counter; }
};
template <class T>
class BoundNoopUpDownCounter : public BoundUpDownCounter<T>
{
public:
BoundNoopUpDownCounter() = default;
BoundNoopUpDownCounter(nostd::string_view /*name*/,
nostd::string_view /*description*/,
nostd::string_view /*unit*/,
bool /*enabled*/)
{}
virtual void add(T value) override {}
virtual bool IsEnabled() override { return false; }
virtual nostd::string_view GetName() override { return nostd::string_view(""); }
virtual nostd::string_view GetDescription() override { return nostd::string_view(""); }
virtual nostd::string_view GetUnits() override { return nostd::string_view(""); }
virtual InstrumentKind GetKind() override { return InstrumentKind::UpDownCounter; }
};
template <class T>
class NoopUpDownCounter : public UpDownCounter<T>
{
public:
NoopUpDownCounter() = default;
NoopUpDownCounter(nostd::string_view /*name*/,
nostd::string_view /*description*/,
nostd::string_view /*unit*/,
bool /*enabled*/)
{}
nostd::shared_ptr<BoundNoopUpDownCounter<T>> bindNoopUpDownCounter(
const common::KeyValueIterable & /*labels*/)
{
return nostd::shared_ptr<BoundNoopUpDownCounter<T>>(new BoundNoopUpDownCounter<T>());
}
virtual void add(T value, const common::KeyValueIterable & /*labels*/) override {}
virtual void update(T value, const common::KeyValueIterable & /*labels*/) override {}
virtual bool IsEnabled() override { return false; }
virtual nostd::string_view GetName() override { return nostd::string_view(""); }
virtual nostd::string_view GetDescription() override { return nostd::string_view(""); }
virtual nostd::string_view GetUnits() override { return nostd::string_view(""); }
virtual InstrumentKind GetKind() override { return InstrumentKind::UpDownCounter; }
};
template <class T>
class BoundNoopValueRecorder : public BoundValueRecorder<T>
{
public:
BoundNoopValueRecorder() = default;
BoundNoopValueRecorder(nostd::string_view /*name*/,
nostd::string_view /*description*/,
nostd::string_view /*unit*/,
bool /*enabled*/)
{}
virtual void record(T value) override {}
virtual bool IsEnabled() override { return false; }
virtual nostd::string_view GetName() override { return nostd::string_view(""); }
virtual nostd::string_view GetDescription() override { return nostd::string_view(""); }
virtual nostd::string_view GetUnits() override { return nostd::string_view(""); }
virtual InstrumentKind GetKind() override { return InstrumentKind::ValueRecorder; }
};
template <class T>
class NoopValueRecorder : public ValueRecorder<T>
{
public:
NoopValueRecorder() = default;
NoopValueRecorder(nostd::string_view /*name*/,
nostd::string_view /*description*/,
nostd::string_view /*unit*/,
bool /*enabled*/)
{}
nostd::shared_ptr<BoundNoopValueRecorder<T>> bindNoopValueRecorder(
const common::KeyValueIterable & /*labels*/)
{
return nostd::shared_ptr<BoundNoopValueRecorder<T>>(new BoundNoopValueRecorder<T>());
}
virtual void record(T value, const common::KeyValueIterable & /*labels*/) override {}
virtual void update(T value, const common::KeyValueIterable & /*labels*/) override {}
virtual bool IsEnabled() override { return false; }
virtual nostd::string_view GetName() override { return nostd::string_view(""); }
virtual nostd::string_view GetDescription() override { return nostd::string_view(""); }
virtual nostd::string_view GetUnits() override { return nostd::string_view(""); }
virtual InstrumentKind GetKind() override { return InstrumentKind::ValueRecorder; }
};
/**
* No-op implementation of Meter. This class should not be used directly.
*/
class NoopMeter : public Meter
{
public:
NoopMeter() = default;
/**
*
* Creates a new NoopCounter<T> and returns a shared ptr to that counter.
*
* @param name the name of the instrument.
* @param description a brief description of the instrument.
* @param unit the unit of metric values following https://unitsofmeasure.org/ucum.html.
* @param enabled a boolean that turns the metric instrument on and off.
* @return
*/
nostd::shared_ptr<Counter<short>> NewShortCounter(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) override
{
return nostd::shared_ptr<Counter<short>>{
new NoopCounter<short>(name, description, unit, enabled)};
}
nostd::shared_ptr<Counter<int>> NewIntCounter(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) override
{
return nostd::shared_ptr<Counter<int>>{new NoopCounter<int>(name, description, unit, enabled)};
}
nostd::shared_ptr<Counter<float>> NewFloatCounter(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) override
{
return nostd::shared_ptr<Counter<float>>{
new NoopCounter<float>(name, description, unit, enabled)};
}
nostd::shared_ptr<Counter<double>> NewDoubleCounter(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) override
{
return nostd::shared_ptr<Counter<double>>{
new NoopCounter<double>(name, description, unit, enabled)};
}
/**
*
* Creates a new NoopCounter<T> and returns a shared ptr to that counter.
*
* @param name the name of the instrument.
* @param description a brief description of the instrument.
* @param unit the unit of metric values following https://unitsofmeasure.org/ucum.html.
* @param enabled a boolean that turns the metric instrument on and off.
* @return
*/
nostd::shared_ptr<UpDownCounter<short>> NewShortUpDownCounter(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) override
{
return nostd::shared_ptr<UpDownCounter<short>>{
new NoopUpDownCounter<short>(name, description, unit, enabled)};
}
nostd::shared_ptr<UpDownCounter<int>> NewIntUpDownCounter(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) override
{
return nostd::shared_ptr<UpDownCounter<int>>{
new NoopUpDownCounter<int>(name, description, unit, enabled)};
}
nostd::shared_ptr<UpDownCounter<float>> NewFloatUpDownCounter(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) override
{
return nostd::shared_ptr<UpDownCounter<float>>{
new NoopUpDownCounter<float>(name, description, unit, enabled)};
}
nostd::shared_ptr<UpDownCounter<double>> NewDoubleUpDownCounter(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) override
{
return nostd::shared_ptr<UpDownCounter<double>>{
new NoopUpDownCounter<double>(name, description, unit, enabled)};
}
/**
*
* Creates a new ValueRecorder<T> and returns a shared ptr to that counter.
*
* @param name the name of the instrument.
* @param description a brief description of the instrument.
* @param unit the unit of metric values following https://unitsofmeasure.org/ucum.html.
* @param enabled a boolean that turns the metric instrument on and off.
* @return
*/
nostd::shared_ptr<ValueRecorder<short>> NewShortValueRecorder(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) override
{
return nostd::shared_ptr<ValueRecorder<short>>{
new NoopValueRecorder<short>(name, description, unit, enabled)};
}
nostd::shared_ptr<ValueRecorder<int>> NewIntValueRecorder(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) override
{
return nostd::shared_ptr<ValueRecorder<int>>{
new NoopValueRecorder<int>(name, description, unit, enabled)};
}
nostd::shared_ptr<ValueRecorder<float>> NewFloatValueRecorder(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) override
{
return nostd::shared_ptr<ValueRecorder<float>>{
new NoopValueRecorder<float>(name, description, unit, enabled)};
}
nostd::shared_ptr<ValueRecorder<double>> NewDoubleValueRecorder(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) override
{
return nostd::shared_ptr<ValueRecorder<double>>{
new NoopValueRecorder<double>(name, description, unit, enabled)};
}
/**
*
* Creates a new SumObserver<T> and returns a shared ptr to that counter.
*
* @param name the name of the instrument.
* @param description a brief description of the instrument.
* @param unit the unit of metric values following https://unitsofmeasure.org/ucum.html.
* @param enabled a boolean that turns the metric instrument on and off.
* @return
*/
nostd::shared_ptr<SumObserver<short>> NewShortSumObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(ObserverResult<short>)) override
{
return nostd::shared_ptr<SumObserver<short>>{
new NoopSumObserver<short>(name, description, unit, enabled, callback)};
}
nostd::shared_ptr<SumObserver<int>> NewIntSumObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(ObserverResult<int>)) override
{
return nostd::shared_ptr<SumObserver<int>>{
new NoopSumObserver<int>(name, description, unit, enabled, callback)};
}
nostd::shared_ptr<SumObserver<float>> NewFloatSumObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(ObserverResult<float>)) override
{
return nostd::shared_ptr<SumObserver<float>>{
new NoopSumObserver<float>(name, description, unit, enabled, callback)};
}
nostd::shared_ptr<SumObserver<double>> NewDoubleSumObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(ObserverResult<double>)) override
{
return nostd::shared_ptr<SumObserver<double>>{
new NoopSumObserver<double>(name, description, unit, enabled, callback)};
}
/**
*
* Creates a new UpDownSumObserver<T> and returns a shared ptr to that counter.
*
* @param name the name of the instrument.
* @param description a brief description of the instrument.
* @param unit the unit of metric values following https://unitsofmeasure.org/ucum.html.
* @param enabled a boolean that turns the metric instrument on and off.
* @return
*/
nostd::shared_ptr<UpDownSumObserver<short>> NewShortUpDownSumObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(ObserverResult<short>)) override
{
return nostd::shared_ptr<UpDownSumObserver<short>>{
new NoopUpDownSumObserver<short>(name, description, unit, enabled, callback)};
}
nostd::shared_ptr<UpDownSumObserver<int>> NewIntUpDownSumObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(ObserverResult<int>)) override
{
return nostd::shared_ptr<UpDownSumObserver<int>>{
new NoopUpDownSumObserver<int>(name, description, unit, enabled, callback)};
}
nostd::shared_ptr<UpDownSumObserver<float>> NewFloatUpDownSumObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(ObserverResult<float>)) override
{
return nostd::shared_ptr<UpDownSumObserver<float>>{
new NoopUpDownSumObserver<float>(name, description, unit, enabled, callback)};
}
nostd::shared_ptr<UpDownSumObserver<double>> NewDoubleUpDownSumObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(ObserverResult<double>)) override
{
return nostd::shared_ptr<UpDownSumObserver<double>>{
new NoopUpDownSumObserver<double>(name, description, unit, enabled, callback)};
}
/**
*
* Creates a new ValueObserverObserver<T> and returns a shared ptr to that counter.
*
* @param name the name of the instrument.
* @param description a brief description of the instrument.
* @param unit the unit of metric values following https://unitsofmeasure.org/ucum.html.
* @param enabled a boolean that turns the metric instrument on and off.
* @return
*/
nostd::shared_ptr<ValueObserver<short>> NewShortValueObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(ObserverResult<short>)) override
{
return nostd::shared_ptr<ValueObserver<short>>{
new NoopValueObserver<short>(name, description, unit, enabled, callback)};
}
nostd::shared_ptr<ValueObserver<int>> NewIntValueObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(ObserverResult<int>)) override
{
return nostd::shared_ptr<ValueObserver<int>>{
new NoopValueObserver<int>(name, description, unit, enabled, callback)};
}
nostd::shared_ptr<ValueObserver<float>> NewFloatValueObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(ObserverResult<float>)) override
{
return nostd::shared_ptr<ValueObserver<float>>{
new NoopValueObserver<float>(name, description, unit, enabled, callback)};
}
nostd::shared_ptr<ValueObserver<double>> NewDoubleValueObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(ObserverResult<double>)) override
{
return nostd::shared_ptr<ValueObserver<double>>{
new NoopValueObserver<double>(name, description, unit, enabled, callback)};
}
/**
*
* Utility method that allows users to atomically record measurements to a set of
* synchronous metric instruments with a common set of labels.
*
* @param labels the set of labels to associate with this recorder.
* @param instrs the instruments to record to.
* @param values the value to record to those instruments.
*/
void RecordShortBatch(const common::KeyValueIterable &labels,
nostd::span<SynchronousInstrument<short> *> instruments,
nostd::span<const short> values) noexcept override
{
// No-op
}
void RecordIntBatch(const common::KeyValueIterable &labels,
nostd::span<SynchronousInstrument<int> *> instruments,
nostd::span<const int> values) noexcept override
{
// No-op
}
void RecordFloatBatch(const common::KeyValueIterable &labels,
nostd::span<SynchronousInstrument<float> *> instruments,
nostd::span<const float> values) noexcept override
{
// No-op
}
void RecordDoubleBatch(const common::KeyValueIterable &labels,
nostd::span<SynchronousInstrument<double> *> instruments,
nostd::span<const double> values) noexcept override
{
// No-op
}
};
class NoopMeterProvider final : public opentelemetry::metrics::MeterProvider
{
public:
NoopMeterProvider()
: meter_{nostd::shared_ptr<opentelemetry::metrics::NoopMeter>(
new opentelemetry::metrics::NoopMeter)}
{}
nostd::shared_ptr<opentelemetry::metrics::Meter> GetMeter(
nostd::string_view library_name,
nostd::string_view library_version) override
{
return meter_;
}
private:
nostd::shared_ptr<opentelemetry::metrics::Meter> meter_;
};
} // namespace metrics
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,41 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef ENABLE_METRICS_PREVIEW
# include "opentelemetry/_metrics/instrument.h"
# include "opentelemetry/nostd/shared_ptr.h"
OPENTELEMETRY_BEGIN_NAMESPACE
namespace metrics
{
/**
* ObserverResult class is necessary for the callback recording asynchronous
* instrument use. Callback functions asynchronous instruments are designed to
* accept a single ObserverResult object and update using its pointer to the
* instrument itself.
*/
template <class T>
class ObserverResult
{
public:
ObserverResult() = default;
ObserverResult(AsynchronousInstrument<T> *instrument) : instrument_(instrument) {}
virtual void observe(T value, const common::KeyValueIterable &labels)
{
instrument_->observe(value, labels);
}
private:
AsynchronousInstrument<T> *instrument_;
};
} // namespace metrics
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,60 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef ENABLE_METRICS_PREVIEW
# include <mutex>
# include "opentelemetry/_metrics/meter_provider.h"
# include "opentelemetry/_metrics/noop.h"
# include "opentelemetry/common/macros.h"
# include "opentelemetry/common/spin_lock_mutex.h"
# include "opentelemetry/nostd/shared_ptr.h"
OPENTELEMETRY_BEGIN_NAMESPACE
namespace metrics
{
/**
* Stores the singleton global MeterProvider.
*/
class Provider
{
public:
/**
* Returns the singleton MeterProvider.
*
* By default, a no-op MeterProvider is returned. This will never return a
* nullptr MeterProvider.
*/
static nostd::shared_ptr<MeterProvider> GetMeterProvider() noexcept
{
std::lock_guard<common::SpinLockMutex> guard(GetLock());
return nostd::shared_ptr<MeterProvider>(GetProvider());
}
/**
* Changes the singleton MeterProvider.
*/
static void SetMeterProvider(nostd::shared_ptr<MeterProvider> tp) noexcept
{
std::lock_guard<common::SpinLockMutex> guard(GetLock());
GetProvider() = tp;
}
private:
OPENTELEMETRY_API_SINGLETON static nostd::shared_ptr<MeterProvider> &GetProvider() noexcept
{
static nostd::shared_ptr<MeterProvider> provider(new NoopMeterProvider);
return provider;
}
OPENTELEMETRY_API_SINGLETON static common::SpinLockMutex &GetLock() noexcept
{
static common::SpinLockMutex lock;
return lock;
}
};
} // namespace metrics
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,181 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef ENABLE_METRICS_PREVIEW
# include "opentelemetry/_metrics/instrument.h"
OPENTELEMETRY_BEGIN_NAMESPACE
namespace metrics
{
template <class T>
class BoundCounter : virtual public BoundSynchronousInstrument<T>
{
public:
BoundCounter() = default;
BoundCounter(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
bool enabled);
/*
* Add adds the value to the counter's sum. The labels are already linked * to the instrument
* and are not specified.
*
* @param value the numerical representation of the metric being captured
* @param labels the set of labels, as key-value pairs
*/
virtual void add(T value) = 0;
};
template <class T>
class Counter : virtual public SynchronousInstrument<T>
{
public:
Counter() = default;
Counter(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
bool enabled)
{}
/*
* Bind creates a bound instrument for this counter. The labels are
* associated with values recorded via subsequent calls to Record.
*
* @param labels the set of labels, as key-value pairs.
* @return a BoundIntCounter tied to the specified labels
*/
virtual nostd::shared_ptr<BoundCounter<T>> bindCounter(const common::KeyValueIterable &labels)
{
return nostd::shared_ptr<BoundCounter<T>>();
}
/*
* Add adds the value to the counter's sum. The labels should contain
* the keys and values to be associated with this value. Counters only * accept positive
* valued updates.
*
* @param value the numerical representation of the metric being captured
* @param labels the set of labels, as key-value pairs
*/
virtual void add(T value, const common::KeyValueIterable &labels) = 0;
virtual void update(T value, const common::KeyValueIterable &labels) override = 0;
};
template <class T>
class BoundUpDownCounter : virtual public BoundSynchronousInstrument<T>
{
public:
BoundUpDownCounter() = default;
BoundUpDownCounter(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
bool enabled);
/*
* Add adds the value to the counter's sum. The labels are already linked to * the instrument and
* do not need to specified again. UpDownCounters can accept positive and negative values.
*
* @param value the numerical representation of the metric being captured
* @param labels the set of labels, as key-value pairs
*/
virtual void add(T value) = 0;
};
template <class T>
class UpDownCounter : virtual public SynchronousInstrument<T>
{
public:
UpDownCounter() = default;
UpDownCounter(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
bool enabled);
virtual nostd::shared_ptr<BoundUpDownCounter<T>> bindUpDownCounter(
const common::KeyValueIterable &labels)
{
return nostd::shared_ptr<BoundUpDownCounter<T>>();
}
/*
* Add adds the value to the counter's sum. The labels should contain
* the keys and values to be associated with this value. UpDownCounters can
* accept positive and negative values.
*
* @param value the numerical representation of the metric being captured
* @param labels the set of labels, as key-value pairs
*/
virtual void add(T value, const common::KeyValueIterable &labels) = 0;
virtual void update(T value, const common::KeyValueIterable &labels) override = 0;
};
template <class T>
class BoundValueRecorder : virtual public BoundSynchronousInstrument<T>
{
public:
BoundValueRecorder() = default;
BoundValueRecorder(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
bool enabled);
/*
* Records the value by summing it with previous measurements and checking * previously stored
* minimum and maximum values. The labels associated with * new values are already linked to the
* instrument as it is bound. * ValueRecorders can accept positive and negative values.
*
* @param value the numerical representation of the metric being captured
*/
virtual void record(T value) = 0;
};
template <class T>
class ValueRecorder : virtual public SynchronousInstrument<T>
{
public:
ValueRecorder() = default;
ValueRecorder(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
bool enabled);
virtual nostd::shared_ptr<BoundValueRecorder<T>> bindValueRecorder(
const common::KeyValueIterable &labels)
{
return nostd::shared_ptr<BoundValueRecorder<T>>();
}
/*
* Records the value by summing it with previous measurements and checking * previously stored
* minimum and maximum values. The labels should contain the keys and values to be associated with
* this value. ValueRecorders can accept positive and negative values.
*
* @param value the numerical representation of the metric being captured
* @param labels the set of labels, as key-value pairs
*/
virtual void record(T value, const common::KeyValueIterable &labels) = 0;
virtual void update(T value, const common::KeyValueIterable &labels) override = 0;
};
} // namespace metrics
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -3,11 +3,7 @@ add_subdirectory(context)
add_subdirectory(plugin)
add_subdirectory(nostd)
add_subdirectory(trace)
if(WITH_METRICS_PREVIEW)
add_subdirectory(_metrics)
else()
add_subdirectory(metrics)
endif()
add_subdirectory(metrics)
if(WITH_LOGS_PREVIEW)
add_subdirectory(logs)
endif()

View File

@ -1,50 +0,0 @@
load("//bazel:otel_cc_benchmark.bzl", "otel_cc_benchmark")
cc_test(
name = "meter_provider_test",
srcs = [
"meter_provider_test.cc",
],
tags = [
"api",
"metrics",
"test",
],
deps = [
"//api",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "noop_metrics_test",
srcs = [
"noop_metrics_test.cc",
],
tags = [
"api",
"metrics",
"test",
],
deps = [
"//api",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "noop_instrument_test",
srcs = [
"noop_instrument_test.cc",
],
linkstatic = 1,
tags = [
"api",
"metrics",
"test",
],
deps = [
"//api",
"@com_google_googletest//:gtest_main",
],
)

View File

@ -1,9 +0,0 @@
foreach(testname noop_instrument_test meter_provider_test noop_metrics_test)
add_executable(${testname} "${testname}.cc")
target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT} opentelemetry_api)
gtest_add_tests(
TARGET ${testname}
TEST_PREFIX metrics.
TEST_LIST ${testname})
endforeach()

View File

@ -1,45 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#ifdef ENABLE_METRICS_PREVIEW
# include <gtest/gtest.h>
# include "opentelemetry/_metrics/provider.h"
# include "opentelemetry/nostd/shared_ptr.h"
using opentelemetry::metrics::Meter;
using opentelemetry::metrics::MeterProvider;
using opentelemetry::metrics::Provider;
namespace nostd = opentelemetry::nostd;
class TestProvider : public MeterProvider
{
nostd::shared_ptr<Meter> GetMeter(nostd::string_view library_name,
nostd::string_view library_version) override
{
return nostd::shared_ptr<Meter>(nullptr);
}
};
TEST(Provider, GetMeterProviderDefault)
{
auto tf = Provider::GetMeterProvider();
EXPECT_NE(nullptr, tf);
}
TEST(Provider, SetMeterProvider)
{
auto tf = nostd::shared_ptr<MeterProvider>(new TestProvider());
Provider::SetMeterProvider(tf);
ASSERT_EQ(tf, Provider::GetMeterProvider());
}
TEST(Provider, MultipleMeterProviders)
{
auto tf = nostd::shared_ptr<MeterProvider>(new TestProvider());
Provider::SetMeterProvider(tf);
auto tf2 = nostd::shared_ptr<MeterProvider>(new TestProvider());
Provider::SetMeterProvider(tf2);
ASSERT_NE(Provider::GetMeterProvider(), tf);
}
#endif

View File

@ -1,191 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#ifdef ENABLE_METRICS_PREVIEW
# include <gtest/gtest.h>
# include <cstring>
# include <map>
# include <string>
# include "opentelemetry/_metrics/noop.h"
OPENTELEMETRY_BEGIN_NAMESPACE
namespace metrics
{
void noopIntCallback(ObserverResult<int> result)
{
std::map<std::string, std::string> labels = {{"key", "value"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
result.observe(1, labelkv);
result.observe(-1, labelkv);
}
void noopDoubleCallback(ObserverResult<double> result)
{
std::map<std::string, std::string> labels = {{"key", "value"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
result.observe(1.5, labelkv);
result.observe(-1.5, labelkv);
}
TEST(ValueObserver, Observe)
{
NoopValueObserver<int> alpha("test", "none", "unitless", true, &noopIntCallback);
NoopValueObserver<double> beta("test", "none", "unitless", true, &noopDoubleCallback);
std::map<std::string, std::string> labels = {{"key", "value"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
alpha.observe(1, labelkv);
beta.observe(1.5, labelkv);
}
TEST(SumObserver, DefaultConstruction)
{
NoopSumObserver<int> alpha("test", "none", "unitless", true, &noopIntCallback);
NoopSumObserver<double> beta("test", "none", "unitless", true, &noopDoubleCallback);
std::map<std::string, std::string> labels = {{"key", "value"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
alpha.observe(1, labelkv);
beta.observe(1.5, labelkv);
}
TEST(UpDownSumObserver, DefaultConstruction)
{
NoopUpDownSumObserver<int> alpha("test", "none", "unitless", true, &noopIntCallback);
NoopUpDownSumObserver<double> beta("test", "none", "unitless", true, &noopDoubleCallback);
std::map<std::string, std::string> labels = {{"key", "value"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
alpha.observe(1, labelkv);
beta.observe(1.0, labelkv);
alpha.observe(-1, labelkv);
beta.observe(-1.0, labelkv);
}
TEST(Counter, DefaultConstruction)
{
NoopCounter<int> alpha("test", "none", "unitless", true);
NoopCounter<double> beta("other", "none", "unitless", true);
std::map<std::string, std::string> labels = {{"key", "value"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
alpha.bind(labelkv);
auto gamma = alpha.bindNoopCounter(labelkv);
auto delta = beta.bindNoopCounter(labelkv);
gamma->unbind();
delta->unbind();
}
TEST(Counter, Add)
{
NoopCounter<int> alpha("test", "none", "unitless", true);
NoopCounter<double> beta("other", "none", "unitless", true);
std::map<std::string, std::string> labels = {{"key", "value"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
alpha.add(1, labelkv);
beta.add(1.5, labelkv);
auto gamma = alpha.bindNoopCounter(labelkv);
auto delta = beta.bindNoopCounter(labelkv);
gamma->add(1);
delta->add(1.5);
gamma->unbind();
delta->unbind();
}
TEST(UpDownCounter, DefaultConstruction)
{
NoopUpDownCounter<int> alpha("test", "none", "unitless", true);
NoopUpDownCounter<double> beta("other", "none", "unitless", true);
std::map<std::string, std::string> labels = {{"key", "value"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
alpha.bind(labelkv);
auto gamma = alpha.bindNoopUpDownCounter(labelkv);
auto delta = beta.bindNoopUpDownCounter(labelkv);
gamma->unbind();
delta->unbind();
}
TEST(UpDownCounter, Add)
{
NoopUpDownCounter<int> alpha("test", "none", "unitless", true);
NoopUpDownCounter<double> beta("other", "none", "unitless", true);
std::map<std::string, std::string> labels = {{"key", "value"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
alpha.add(1, labelkv);
beta.add(1.5, labelkv);
auto gamma = alpha.bindNoopUpDownCounter(labelkv);
auto delta = beta.bindNoopUpDownCounter(labelkv);
gamma->add(1);
delta->add(1.0);
gamma->add(-1);
delta->add(-1.0);
gamma->unbind();
delta->unbind();
}
TEST(ValueRecorder, DefaultConstruction)
{
NoopValueRecorder<int> alpha("test", "none", "unitless", true);
NoopValueRecorder<double> beta("other", "none", "unitless", true);
std::map<std::string, std::string> labels = {{"key", "value"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
alpha.bind(labelkv);
auto gamma = alpha.bindNoopValueRecorder(labelkv);
auto delta = beta.bindNoopValueRecorder(labelkv);
gamma->unbind();
delta->unbind();
}
TEST(ValueRecorder, Record)
{
NoopValueRecorder<int> alpha("test", "none", "unitless", true);
NoopValueRecorder<double> beta("other", "none", "unitless", true);
std::map<std::string, std::string> labels = {{"key", "value"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
alpha.record(1, labelkv);
beta.record(1.5, labelkv);
auto gamma = alpha.bindNoopValueRecorder(labelkv);
auto delta = beta.bindNoopValueRecorder(labelkv);
gamma->record(1);
delta->record(1.5);
gamma->unbind();
delta->unbind();
}
} // namespace metrics
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,83 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#ifdef ENABLE_METRICS_PREVIEW
# include <gtest/gtest.h>
# include "opentelemetry/_metrics/instrument.h"
# include "opentelemetry/_metrics/noop.h"
# include "opentelemetry/_metrics/observer_result.h"
# include "opentelemetry/_metrics/sync_instruments.h"
# include <array>
# include <memory>
OPENTELEMETRY_BEGIN_NAMESPACE
using opentelemetry::metrics::Meter;
using opentelemetry::metrics::NoopMeter;
void Callback(opentelemetry::metrics::ObserverResult<int> result)
{
std::map<std::string, std::string> labels = {{"key", "value"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
result.observe(1, labelkv);
}
TEST(NoopTest, CreateInstruments)
{
auto m = std::unique_ptr<Meter>(new NoopMeter{});
// Test instrument constructors
m->NewIntCounter("Test counter", "For testing", "Unitless", true);
m->NewIntUpDownCounter("Test ud counter", "For testing", "Unitless", true);
m->NewIntValueRecorder("Test recorder", "For testing", "Unitless", true);
m->NewIntSumObserver("Test sum obs", "For testing", "Unitless", true, &Callback);
m->NewIntUpDownSumObserver("Test udsum obs", "For testing", "Unitless", true, &Callback);
m->NewIntValueObserver("Test val obs", "For testing", "Unitless", true, &Callback);
}
TEST(NoopMeter, RecordBatch)
{
// Test BatchRecord with all supported types
// Create Counter and call RecordBatch for all four supported types: short, int, float, and double
std::unique_ptr<Meter> m{std::unique_ptr<Meter>(new NoopMeter{})};
std::map<std::string, std::string> labels = {{"Key", "Value"}};
auto labelkv = opentelemetry::common::KeyValueIterableView<decltype(labels)>{labels};
auto s = m->NewShortCounter("Test short counter", "For testing", "Unitless", true);
std::array<metrics::SynchronousInstrument<short> *, 1> siarr{s.get()};
std::array<short, 1> svarr{1};
nostd::span<metrics::SynchronousInstrument<short> *> ssp{siarr};
nostd::span<short> sval{svarr};
m->RecordShortBatch(labelkv, ssp, sval);
auto i = m->NewIntCounter("Test int counter", "For testing", "Unitless", true);
std::array<metrics::SynchronousInstrument<int> *, 1> iiarr{i.get()};
std::array<int, 1> ivarr{1};
nostd::span<metrics::SynchronousInstrument<int> *> isp{iiarr};
nostd::span<int> ival{ivarr};
m->RecordIntBatch(labelkv, isp, ival);
auto f = m->NewFloatCounter("Test int counter", "For testing", "Unitless", true);
std::array<metrics::SynchronousInstrument<float> *, 1> fiarr{f.get()};
std::array<float, 1> fvarr{1.0f};
nostd::span<metrics::SynchronousInstrument<float> *> fsp{fiarr};
nostd::span<float> fval{fvarr};
m->RecordFloatBatch(labelkv, fsp, fval);
auto d = m->NewDoubleCounter("Test int counter", "For testing", "Unitless", true);
std::array<metrics::SynchronousInstrument<double> *, 1> diarr{d.get()};
std::array<double, 1> dvarr{1.0f};
nostd::span<metrics::SynchronousInstrument<double> *> dsp{diarr};
nostd::span<double> dval{dvarr};
m->RecordDoubleBatch(labelkv, dsp, dval);
}
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -41,7 +41,6 @@
# opentelemetry-cpp::ostream_log_record_exporter - Imported target of opentelemetry-cpp::ostream_log_record_exporter
# opentelemetry-cpp::ostream_metrics_exporter - Imported target of opentelemetry-cpp::ostream_metrics_exporter
# opentelemetry-cpp::ostream_span_exporter - Imported target of opentelemetry-cpp::ostream_span_exporter
# opentelemetry-cpp::prometheus_exporter_deprecated - Imported target of opentelemetry-cpp::prometheus_exporter_deprecated
# opentelemetry-cpp::elasticsearch_log_record_exporter - Imported target of opentelemetry-cpp::elasticsearch_log_record_exporter
# opentelemetry-cpp::etw_exporter - Imported target of opentelemetry-cpp::etw_exporter
# opentelemetry-cpp::jaeger_trace_exporter - Imported target of opentelemetry-cpp::jaeger_trace_exporter

View File

@ -1,17 +1,3 @@
cc_binary(
name = "metrics_simple_example",
srcs = [
"main.cc",
],
linkopts = ["-pthread"],
tags = ["ostream"],
deps = [
"//api",
"//exporters/ostream:ostream_metrics_exporter_deprecated",
"//sdk/src/_metrics:metrics_deprecated",
],
)
cc_binary(
name = "metrics_ostream_example",
srcs = [

View File

@ -1,118 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#ifdef ENABLE_METRICS_PREVIEW
# include "opentelemetry/_metrics/provider.h"
# include "opentelemetry/exporters/ostream/metrics_exporter.h"
# include "opentelemetry/sdk/_metrics/controller.h"
# include "opentelemetry/sdk/_metrics/meter.h"
# include "opentelemetry/sdk/_metrics/meter_provider.h"
# include "opentelemetry/sdk/_metrics/ungrouped_processor.h"
namespace metric_sdk = opentelemetry::sdk::metrics;
namespace nostd = opentelemetry::nostd;
namespace common = opentelemetry::common;
namespace exportermetrics = opentelemetry::exporter::metrics;
namespace metrics_api = opentelemetry::metrics;
int main()
{
// Initialize and set the global MeterProvider
auto provider = nostd::shared_ptr<metrics_api::MeterProvider>(new metric_sdk::MeterProvider);
metrics_api::Provider::SetMeterProvider(provider);
// Get the Meter from the MeterProvider
nostd::shared_ptr<metrics_api::Meter> meter = provider->GetMeter("Test", "0.1.0");
// Create the controller with Stateless Metrics Processor
metric_sdk::PushController ControllerStateless(
meter,
std::unique_ptr<metric_sdk::MetricsExporter>(new exportermetrics::OStreamMetricsExporter),
std::shared_ptr<metric_sdk::MetricsProcessor>(
new metric_sdk::UngroupedMetricsProcessor(false)),
.05);
// Create and instrument
auto intupdowncounter = meter->NewIntUpDownCounter("UpDownCounter", "None", "none", true);
auto intcounter = meter->NewIntCounter("Counter", "none", "none", true);
// Create a labelset
std::map<std::string, std::string> labels = {{"key", "value"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
// Create arrays of instrument and values to add to them
metrics_api::SynchronousInstrument<int> *iinstr_arr[] = {intupdowncounter.get(),
intcounter.get()};
int ivalues_arr[] = {10, 5};
// Change the arrays to be nostd::spans
nostd::span<metrics_api::SynchronousInstrument<int> *> instrument_span{iinstr_arr};
nostd::span<const int, 2> instrument_values{ivalues_arr};
/**
* First way of updating an instrument, RecordBatch. We can update multiple instruments at once by
* using a span of instruments and a span of values. This RecordBatch will update the ith
* instrument with the ith value.
**/
std::cout << "Example 1" << std::endl;
ControllerStateless.start();
// Updating multiple instruments with the same labelset
meter->RecordIntBatch(labelkv, instrument_span, instrument_values);
ControllerStateless.stop();
/**
* Second way of updating an instrument, bind then add. In this method the user binds an
*instrument to a labelset Then add to the bounded instrument, then unbind.
**/
std::cout << "Example 2" << std::endl;
ControllerStateless.start();
auto boundintupdowncounter = intupdowncounter->bindUpDownCounter(labelkv);
boundintupdowncounter->add(50);
boundintupdowncounter->unbind();
ControllerStateless.stop();
/**
* The Third and final way is to add a value with a labelset at the same time. This also shows
* The difference between using a Stateless and Stateful Processor
*/
// Start exporting from the Controller with Stateless Processor
std::cout << "-----"
<< " Stateless Processor "
<< "-----" << std::endl;
ControllerStateless.start();
for (int i = 0; i < 20; i++)
{
intupdowncounter->add(i, labelkv);
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
ControllerStateless.stop();
// Do the same thing for stateful to see the difference
metric_sdk::PushController ControllerStateful(
meter,
std::unique_ptr<metric_sdk::MetricsExporter>(new exportermetrics::OStreamMetricsExporter),
std::shared_ptr<metric_sdk::MetricsProcessor>(
new metric_sdk::UngroupedMetricsProcessor(true)),
.05);
// Start exporting from the Controller with Stateful Processor
std::cout << "-----"
<< " Stateful Processor "
<< "-----" << std::endl;
ControllerStateful.start();
for (int i = 0; i < 20; i++)
{
intupdowncounter->add(i, labelkv);
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
ControllerStateful.stop();
}
#else
int main()
{
// empty
}
#endif

View File

@ -29,21 +29,6 @@ cc_test(
],
)
cc_library(
name = "ostream_metrics_exporter_deprecated",
srcs = [
"src/metrics_exporter.cc",
],
hdrs = [
"include/opentelemetry/exporters/ostream/metrics_exporter.h",
],
strip_include_prefix = "include",
tags = ["ostream"],
deps = [
"//sdk/src/_metrics:metrics_deprecated",
],
)
cc_library(
name = "ostream_metric_exporter",
srcs = [
@ -76,19 +61,6 @@ cc_test(
],
)
cc_test(
name = "ostream_metrics_test_deprecated",
srcs = ["test/ostream_metrics_test.cc"],
tags = [
"ostream",
"test",
],
deps = [
":ostream_metrics_exporter_deprecated",
"@com_google_googletest//:gtest_main",
],
)
cc_library(
name = "ostream_span_exporter",
srcs = [

View File

@ -1,166 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef ENABLE_METRICS_PREVIEW
# include <iostream>
# include <string>
# include "opentelemetry/sdk/_metrics/aggregator/exact_aggregator.h"
# include "opentelemetry/sdk/_metrics/aggregator/gauge_aggregator.h"
# include "opentelemetry/sdk/_metrics/aggregator/histogram_aggregator.h"
# include "opentelemetry/sdk/_metrics/exporter.h"
# include "opentelemetry/sdk/_metrics/record.h"
OPENTELEMETRY_BEGIN_NAMESPACE
namespace exporter
{
namespace metrics
{
/**
* The OStreamMetricsExporter exports record data through an ostream
*/
class OStreamMetricsExporter final : public opentelemetry::sdk::metrics::MetricsExporter
{
public:
/**
* Create an OStreamMetricsExporter. This constructor takes in a reference to an ostream that the
* export() function will send span data into.
* The default ostream is set to stdout
*/
explicit OStreamMetricsExporter(std::ostream &sout = std::cout) noexcept;
sdk::common::ExportResult Export(
const std::vector<opentelemetry::sdk::metrics::Record> &records) noexcept override;
private:
std::ostream &sout_;
/**
* Send specific data from the given AggregatorVariant based on what AggregatorKind
* it is holding. Each Aggregator holds data differently, so each have their own
* custom printing.
*/
template <typename T>
void PrintAggregatorVariant(opentelemetry::sdk::metrics::AggregatorVariant value)
{
auto agg = nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>>>(value);
auto aggKind = agg->get_aggregator_kind();
if (!agg)
return;
switch (aggKind)
{
case opentelemetry::sdk::metrics::AggregatorKind::Counter: {
sout_ << "\n sum : " << agg->get_checkpoint()[0];
}
break;
case opentelemetry::sdk::metrics::AggregatorKind::MinMaxSumCount: {
auto mmsc = agg->get_checkpoint();
sout_ << "\n min : " << mmsc[0] << "\n max : " << mmsc[1]
<< "\n sum : " << mmsc[2] << "\n count : " << mmsc[3];
}
break;
case opentelemetry::sdk::metrics::AggregatorKind::Gauge: {
auto timestamp = agg->get_checkpoint_timestamp();
sout_ << "\n last value : " << agg->get_checkpoint()[0]
<< "\n timestamp : " << std::to_string(timestamp.time_since_epoch().count());
}
break;
case opentelemetry::sdk::metrics::AggregatorKind::Exact: {
// TODO: Find better way to print quantiles
if (agg->get_quant_estimation())
{
sout_ << "\n quantiles : "
<< "[0: " << agg->get_quantiles(0) << ", "
<< ".25: " << agg->get_quantiles(.25) << ", "
<< ".50: " << agg->get_quantiles(.50) << ", "
<< ".75: " << agg->get_quantiles(.75) << ", "
<< "1: " << agg->get_quantiles(1) << ']';
}
else
{
auto vec = agg->get_checkpoint();
size_t size = vec.size();
size_t i = 1;
sout_ << "\n values : " << '[';
for (auto val : vec)
{
sout_ << val;
if (i != size)
sout_ << ", ";
i++;
}
sout_ << ']';
}
}
break;
case opentelemetry::sdk::metrics::AggregatorKind::Histogram: {
auto boundaries = agg->get_boundaries();
auto counts = agg->get_counts();
size_t boundaries_size = boundaries.size();
size_t counts_size = counts.size();
sout_ << "\n buckets : " << '[';
for (size_t i = 0; i < boundaries_size; i++)
{
sout_ << boundaries[i];
if (i != boundaries_size - 1)
sout_ << ", ";
}
sout_ << ']';
sout_ << "\n counts : " << '[';
for (size_t i = 0; i < counts_size; i++)
{
sout_ << counts[i];
if (i != counts_size - 1)
sout_ << ", ";
}
sout_ << ']';
}
break;
case opentelemetry::sdk::metrics::AggregatorKind::Sketch: {
auto boundaries = agg->get_boundaries();
auto counts = agg->get_counts();
size_t boundaries_size = boundaries.size();
size_t counts_size = counts.size();
sout_ << "\n buckets : " << '[';
for (size_t i = 0; i < boundaries_size; i++)
{
sout_ << boundaries[i];
if (i != boundaries_size - 1)
sout_ << ", ";
}
sout_ << ']';
sout_ << "\n counts : " << '[';
for (size_t i = 0; i < counts_size; i++)
{
sout_ << counts[i];
if (i != counts_size - 1)
sout_ << ", ";
}
sout_ << ']';
}
break;
}
}
};
} // namespace metrics
} // namespace exporter
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,295 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#include <gtest/gtest.h>
#ifdef ENABLE_METRICS_PREVIEW
# include "opentelemetry/exporters/ostream/metrics_exporter.h"
# include "opentelemetry/sdk/_metrics/aggregator/counter_aggregator.h"
# include "opentelemetry/sdk/_metrics/aggregator/exact_aggregator.h"
# include "opentelemetry/sdk/_metrics/aggregator/gauge_aggregator.h"
# include "opentelemetry/sdk/_metrics/aggregator/min_max_sum_count_aggregator.h"
# include "opentelemetry/sdk/_metrics/aggregator/sketch_aggregator.h"
# include "opentelemetry/sdk/_metrics/exporter.h"
# include "opentelemetry/sdk/_metrics/record.h"
# include <iostream>
namespace metric_sdk = opentelemetry::sdk::metrics;
namespace metrics_api = opentelemetry::metrics;
namespace nostd = opentelemetry::nostd;
namespace exportermetrics = opentelemetry::exporter::metrics;
TEST(OStreamMetricsExporter, PrintCounter)
{
auto exporter =
std::unique_ptr<metric_sdk::MetricsExporter>(new exportermetrics::OStreamMetricsExporter);
auto aggregator = std::shared_ptr<metric_sdk::Aggregator<double>>(
new metric_sdk::CounterAggregator<double>(metrics_api::InstrumentKind::Counter));
aggregator->update(5.5);
aggregator->checkpoint();
metric_sdk::Record r("name", "description", "labels", aggregator);
std::vector<metric_sdk::Record> records;
records.push_back(r);
// Create stringstream to redirect to
std::stringstream stdoutOutput;
// Save cout's buffer here
std::streambuf *sbuf = std::cout.rdbuf();
// Redirect cout to our stringstream buffer
std::cout.rdbuf(stdoutOutput.rdbuf());
exporter->Export(records);
std::cout.rdbuf(sbuf);
std::string expectedOutput =
"{\n"
" name : name\n"
" description : description\n"
" labels : labels\n"
" sum : 5.5\n"
"}\n";
ASSERT_EQ(stdoutOutput.str(), expectedOutput);
}
TEST(OStreamMetricsExporter, PrintMinMaxSumCount)
{
auto exporter =
std::unique_ptr<metric_sdk::MetricsExporter>(new exportermetrics::OStreamMetricsExporter);
auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
new metric_sdk::MinMaxSumCountAggregator<int>(metrics_api::InstrumentKind::Counter));
aggregator->update(1);
aggregator->update(2);
aggregator->checkpoint();
metric_sdk::Record r("name", "description", "labels", aggregator);
std::vector<metric_sdk::Record> records;
records.push_back(r);
// Create stringstream to redirect to
std::stringstream stdoutOutput;
// Save cout's buffer here
std::streambuf *sbuf = std::cout.rdbuf();
// Redirect cout to our stringstream buffer
std::cout.rdbuf(stdoutOutput.rdbuf());
exporter->Export(records);
std::cout.rdbuf(sbuf);
std::string expectedOutput =
"{\n"
" name : name\n"
" description : description\n"
" labels : labels\n"
" min : 1\n"
" max : 2\n"
" sum : 3\n"
" count : 2\n"
"}\n";
ASSERT_EQ(stdoutOutput.str(), expectedOutput);
}
TEST(OStreamMetricsExporter, PrintGauge)
{
auto exporter =
std::unique_ptr<metric_sdk::MetricsExporter>(new exportermetrics::OStreamMetricsExporter);
auto aggregator = std::shared_ptr<metric_sdk::Aggregator<short>>(
new metric_sdk::GaugeAggregator<short>(metrics_api::InstrumentKind::Counter));
aggregator->update(1);
aggregator->update(9);
aggregator->checkpoint();
metric_sdk::Record r("name", "description", "labels", aggregator);
std::vector<metric_sdk::Record> records;
records.push_back(r);
// Create stringstream to redirect to
std::stringstream stdoutOutput;
// Save cout's buffer here
std::streambuf *sbuf = std::cout.rdbuf();
// Redirect cout to our stringstream buffer
std::cout.rdbuf(stdoutOutput.rdbuf());
exporter->Export(records);
std::cout.rdbuf(sbuf);
std::string expectedOutput =
"{\n"
" name : name\n"
" description : description\n"
" labels : labels\n"
" last value : 9\n"
" timestamp : " +
std::to_string(aggregator->get_checkpoint_timestamp().time_since_epoch().count()) +
"\n"
"}\n";
ASSERT_EQ(stdoutOutput.str(), expectedOutput);
}
TEST(OStreamMetricsExporter, PrintExact)
{
auto exporter =
std::unique_ptr<metric_sdk::MetricsExporter>(new exportermetrics::OStreamMetricsExporter);
auto aggregator = std::shared_ptr<metric_sdk::Aggregator<short>>(
new metric_sdk::ExactAggregator<short>(metrics_api::InstrumentKind::Counter, true));
auto aggregator2 = std::shared_ptr<metric_sdk::Aggregator<short>>(
new metric_sdk::ExactAggregator<short>(metrics_api::InstrumentKind::Counter, false));
for (int i = 0; i < 10; i++)
{
aggregator->update(i);
aggregator2->update(i);
}
aggregator->checkpoint();
aggregator2->checkpoint();
metric_sdk::Record r("name", "description", "labels", aggregator);
metric_sdk::Record r2("name", "description", "labels", aggregator2);
std::vector<metric_sdk::Record> records;
records.push_back(r);
records.push_back(r2);
// Create stringstream to redirect to
std::stringstream stdoutOutput;
// Save cout's buffer here
std::streambuf *sbuf = std::cout.rdbuf();
// Redirect cout to our stringstream buffer
std::cout.rdbuf(stdoutOutput.rdbuf());
exporter->Export(records);
std::cout.rdbuf(sbuf);
std::string expectedOutput =
"{\n"
" name : name\n"
" description : description\n"
" labels : labels\n"
" quantiles : [0: 0, .25: 3, .50: 5, .75: 7, 1: 9]\n"
"}\n"
"{\n"
" name : name\n"
" description : description\n"
" labels : labels\n"
" values : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n"
"}\n";
ASSERT_EQ(stdoutOutput.str(), expectedOutput);
}
TEST(OStreamMetricsExporter, PrintHistogram)
{
auto exporter =
std::unique_ptr<metric_sdk::MetricsExporter>(new exportermetrics::OStreamMetricsExporter);
std::vector<double> boundaries{10, 20, 30, 40, 50};
auto aggregator = std::shared_ptr<metric_sdk::Aggregator<float>>(
new metric_sdk::HistogramAggregator<float>(metrics_api::InstrumentKind::Counter, boundaries));
for (float i = 0; i < 60; i++)
{
aggregator->update(i);
}
aggregator->checkpoint();
metric_sdk::Record r("name", "description", "labels", aggregator);
std::vector<metric_sdk::Record> records;
records.push_back(r);
// Create stringstream to redirect to
std::stringstream stdoutOutput;
// Save cout's buffer here
std::streambuf *sbuf = std::cout.rdbuf();
// Redirect cout to our stringstream buffer
std::cout.rdbuf(stdoutOutput.rdbuf());
exporter->Export(records);
std::cout.rdbuf(sbuf);
std::string expectedOutput =
"{\n"
" name : name\n"
" description : description\n"
" labels : labels\n"
" buckets : [10, 20, 30, 40, 50]\n"
" counts : [10, 10, 10, 10, 10, 10]\n"
"}\n";
ASSERT_EQ(stdoutOutput.str(), expectedOutput);
}
TEST(OStreamMetricsExporter, PrintSketch)
{
auto exporter =
std::unique_ptr<metric_sdk::MetricsExporter>(new exportermetrics::OStreamMetricsExporter);
std::vector<double> boundaries{1, 3, 5, 7, 9};
auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
new metric_sdk::SketchAggregator<int>(metrics_api::InstrumentKind::Counter, .000005));
for (int i = 0; i < 10; i++)
{
aggregator->update(i);
}
aggregator->checkpoint();
metric_sdk::Record r("name", "description", "labels", aggregator);
std::vector<metric_sdk::Record> records;
records.push_back(r);
// Create stringstream to redirect to
std::stringstream stdoutOutput;
// Save cout's buffer here
std::streambuf *sbuf = std::cout.rdbuf();
// Redirect cout to our stringstream buffer
std::cout.rdbuf(stdoutOutput.rdbuf());
exporter->Export(records);
std::cout.rdbuf(sbuf);
std::string expectedOutput =
"{\n"
" name : name\n"
" description : description\n"
" labels : labels\n"
" buckets : [0, 0.999995, 2, 3.00001, 4, 4.99999, 5.99997, 7.00003, 8.00003, 9]\n"
" counts : [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]\n"
"}\n";
ASSERT_EQ(stdoutOutput.str(), expectedOutput);
}
#else
TEST(OStreamMetricsExporter, DummyTest)
{
// empty
}
#endif

View File

@ -14,78 +14,6 @@
package(default_visibility = ["//visibility:public"])
cc_library(
name = "prometheus_exporter_deprecated",
srcs = [
"src/prometheus_exporter.cc",
],
hdrs = [
"include/opentelemetry/exporters/prometheus/prometheus_exporter.h",
],
strip_include_prefix = "include",
tags = ["prometheus"],
deps = [
":prometheus_collector_deprecated",
":prometheus_exporter_utils_deprecated",
"//api",
"//sdk:headers",
"@com_github_jupp0r_prometheus_cpp//core",
"@com_github_jupp0r_prometheus_cpp//pull",
],
)
cc_library(
name = "prometheus_exporter_utils_deprecated",
srcs = [
"src/prometheus_exporter_utils.cc",
],
hdrs = [
"include/opentelemetry/exporters/prometheus/prometheus_exporter_utils.h",
],
strip_include_prefix = "include",
tags = ["prometheus"],
deps = [
"//api",
"//sdk:headers",
"@com_github_jupp0r_prometheus_cpp//core",
"@com_github_jupp0r_prometheus_cpp//pull",
],
)
cc_library(
name = "prometheus_collector_deprecated",
srcs = [
"src/prometheus_collector.cc",
],
hdrs = [
"include/opentelemetry/exporters/prometheus/prometheus_collector.h",
],
strip_include_prefix = "include",
tags = ["prometheus"],
deps = [
":prometheus_exporter_utils_deprecated",
"//api",
"//sdk:headers",
"@com_github_jupp0r_prometheus_cpp//core",
"@com_github_jupp0r_prometheus_cpp//pull",
],
)
cc_test(
name = "prometheus_exporter_test_deprecated",
srcs = [
"test/prometheus_exporter_test.cc",
],
tags = [
"prometheus",
"test",
],
deps = [
":prometheus_exporter_deprecated",
"@com_google_googletest//:gtest_main",
],
)
cc_library(
name = "prometheus_exporter",
srcs = [

View File

@ -1,88 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef ENABLE_METRICS_PREVIEW
# include <memory>
# include <mutex>
# include <vector>
# include "opentelemetry/exporters/prometheus/prometheus_exporter_utils.h"
# include "opentelemetry/sdk/_metrics/record.h"
# include "prometheus/collectable.h"
# include "prometheus/metric_family.h"
namespace prometheus_client = ::prometheus;
OPENTELEMETRY_BEGIN_NAMESPACE
namespace exporter
{
namespace prometheus
{
/**
* The Prometheus Collector maintains the intermediate collection in Prometheus Exporter
*/
class PrometheusCollector : public prometheus_client::Collectable
{
public:
/**
* Default Constructor.
*
* This constructor initializes the collection for metrics to export
* in this class with default capacity
*/
explicit PrometheusCollector(size_t max_collection_size = 2048);
/**
* Collects all metrics data from metricsToCollect collection.
*
* @return all metrics in the metricsToCollect snapshot
*/
std::vector<prometheus_client::MetricFamily> Collect() const override;
/**
* This function is called by export() function and add the collection of
* records to the metricsToCollect collection
*
* @param records a collection of records to add to the metricsToCollect collection
*/
void AddMetricData(const std::vector<opentelemetry::sdk::metrics::Record> &records);
/**
* Get the current collection in the collector.
*
* @return the current metricsToCollect collection
*/
std::vector<opentelemetry::sdk::metrics::Record> GetCollection();
/**
* Gets the maximum size of the collection.
*
* @return max collection size
*/
int GetMaxCollectionSize() const;
private:
/**
* Collection of metrics data from the export() function, and to be export
* to user when they send a pull request. This collection is a pointer
* to a collection so Collect() is able to clear the collection, even
* though it is a const function.
*/
std::unique_ptr<std::vector<opentelemetry::sdk::metrics::Record>> metrics_to_collect_;
/**
* Maximum size of the metricsToCollect collection.
*/
size_t max_collection_size_;
/*
* Lock when operating the metricsToCollect collection
*/
mutable std::mutex collection_lock_;
};
} // namespace prometheus
} // namespace exporter
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,98 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef ENABLE_METRICS_PREVIEW
# include <memory>
# include <string>
# include <vector>
# include "opentelemetry/exporters/prometheus/prometheus_collector.h"
# include "opentelemetry/sdk/_metrics/exporter.h"
# include "opentelemetry/sdk/_metrics/record.h"
# include "opentelemetry/version.h"
# include "prometheus/exposer.h"
/**
* This class is an implementation of the MetricsExporter interface and
* exports Prometheus metrics data. Functions in this class should be
* called by the Controller in our data pipeline.
*/
OPENTELEMETRY_BEGIN_NAMESPACE
namespace exporter
{
namespace prometheus
{
class PrometheusExporter : public sdk::metrics::MetricsExporter
{
public:
/**
* Constructor - binds an exposer and collector to the exporter
* @param address: an address for an exposer that exposes
* an HTTP endpoint for the exporter to connect to
*/
PrometheusExporter(std::string &address);
/**
* Exports a batch of Metric Records.
* @param records: a collection of records to export
* @return: returns a ReturnCode detailing a success, or type of failure
*/
sdk::common::ExportResult Export(
const std::vector<sdk::metrics::Record> &records) noexcept override;
/**
* Shuts down the exporter and does cleanup.
* Since Prometheus is a pull based interface,
* we cannot serve data remaining in the intermediate
* collection to to client an HTTP request being sent,
* so we flush the data.
*/
void Shutdown() noexcept;
/**
* @return: returns a shared_ptr to
* the PrometheusCollector instance
*/
std::shared_ptr<PrometheusCollector> &GetCollector();
/**
* @return: Gets the shutdown status of the exporter
*/
bool IsShutdown() const;
private:
/**
* exporter shutdown status
*/
bool is_shutdown_;
/**
* Pointer to a
* PrometheusCollector instance
*/
std::shared_ptr<PrometheusCollector> collector_;
/**
* Pointer to an
* Exposer instance
*/
std::unique_ptr<::prometheus::Exposer> exposer_;
/**
* friend class for testing
*/
friend class PrometheusExporterTest;
/**
* PrometheusExporter constructor with no parameters
* Used for testing only
*/
PrometheusExporter();
};
} // namespace prometheus
} // namespace exporter
OPENTELEMETRY_END_NAMESPACE
#endif // ENABLE_METRICS_PREVIEW

View File

@ -1,171 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef ENABLE_METRICS_PREVIEW
# include <string>
# include <vector>
# include "opentelemetry/sdk/_metrics/record.h"
# include "prometheus/metric_family.h"
OPENTELEMETRY_BEGIN_NAMESPACE
namespace exporter
{
namespace prometheus
{
/**
* The Prometheus Utils contains utility functions for Prometheus Exporter
*/
class PrometheusExporterUtils
{
public:
/**
* Helper function to convert OpenTelemetry metrics data collection
* to Prometheus metrics data collection
*
* @param records a collection of metrics in OpenTelemetry
* @return a collection of translated metrics that is acceptable by Prometheus
*/
static std::vector<::prometheus::MetricFamily> TranslateToPrometheus(
const std::vector<opentelemetry::sdk::metrics::Record> &records);
private:
/**
* Set value to metric family according to record
*/
static void SetMetricFamily(opentelemetry::sdk::metrics::Record &record,
::prometheus::MetricFamily *metric_family);
/**
* Sanitize the given metric name or label according to Prometheus rule.
*
* This function is needed because names in OpenTelemetry can contain
* alphanumeric characters, '_', '.', and '-', whereas in Prometheus the
* name should only contain alphanumeric characters and '_'.
*/
static std::string SanitizeNames(std::string name);
/**
* Set value to metric family for different aggregator
*/
template <typename T>
static void SetMetricFamilyByAggregator(
std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>> aggregator,
std::string labels_str,
::prometheus::MetricFamily *metric_family);
/**
* Translate the OTel metric type to Prometheus metric type
*/
static ::prometheus::MetricType TranslateType(opentelemetry::sdk::metrics::AggregatorKind kind);
/**
* Set metric data for:
* Counter => Prometheus Counter
* Gauge => Prometheus Gauge
*/
template <typename T>
static void SetData(std::vector<T> values,
const std::string &labels,
::prometheus::MetricType type,
std::chrono::nanoseconds time,
::prometheus::MetricFamily *metric_family);
/**
* Set metric data for:
* Histogram => Prometheus Histogram
*/
template <typename T>
static void SetData(std::vector<T> values,
const std::vector<double> &boundaries,
const std::vector<int> &counts,
const std::string &labels,
std::chrono::nanoseconds time,
::prometheus::MetricFamily *metric_family);
/**
* Set metric data for:
* MinMaxSumCount => Prometheus Gauge
* Use Average (sum / count) as the gauge metric
*/
static void SetData(double value,
const std::string &labels,
std::chrono::nanoseconds time,
::prometheus::MetricFamily *metric_family);
/**
* Set metric data for:
* Exact => Prometheus Summary
* Sketch => Prometheus Summary
*/
template <typename T>
static void SetData(std::vector<T> values,
opentelemetry::sdk::metrics::AggregatorKind kind,
const std::vector<T> &quantiles,
const std::string &labels,
std::chrono::nanoseconds time,
::prometheus::MetricFamily *metric_family,
bool do_quantile,
std::vector<double> quantile_points);
/**
* Set time and labels to metric data
*/
static void SetMetricBasic(::prometheus::ClientMetric &metric,
std::chrono::nanoseconds time,
const std::string &labels);
/**
* Parse a string of labels (key:value) into a vector of pairs
* {,}
* {l1:v1,l2:v2,...,}
*/
static std::vector<std::pair<std::string, std::string>> ParseLabel(std::string labels);
/**
* Build a quantiles vector from aggregator
*/
template <typename T>
static std::vector<T> GetQuantilesVector(
std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>> aggregator,
const std::vector<double> &quantile_points);
/**
* Handle Counter and Gauge.
*/
template <typename T>
static void SetValue(std::vector<T> values,
::prometheus::MetricType type,
::prometheus::ClientMetric *metric);
/**
* Handle Gauge from MinMaxSumCount
*/
static void SetValue(double value, ::prometheus::ClientMetric *metric);
/**
* Handle Histogram
*/
template <typename T>
static void SetValue(std::vector<T> values,
std::vector<double> boundaries,
std::vector<int> counts,
::prometheus::ClientMetric *metric);
/**
* Handle Exact and Sketch
*/
template <typename T>
static void SetValue(std::vector<T> values,
opentelemetry::sdk::metrics::AggregatorKind kind,
std::vector<T> quantiles,
::prometheus::ClientMetric *metric,
bool do_quantile,
const std::vector<double> &quantile_points);
};
} // namespace prometheus
} // namespace exporter
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,166 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#ifdef ENABLE_METRICS_PREVIEW
# include <iostream>
# include "opentelemetry/exporters/prometheus/prometheus_collector.h"
namespace metric_sdk = opentelemetry::sdk::metrics;
OPENTELEMETRY_BEGIN_NAMESPACE
namespace exporter
{
namespace prometheus
{
/**
* Default Constructor.
*
* This constructor initializes the collection for metrics to export
* in this class with default capacity
*/
PrometheusCollector::PrometheusCollector(size_t max_collection_size)
: max_collection_size_(max_collection_size)
{
metrics_to_collect_ =
std::unique_ptr<std::vector<metric_sdk::Record>>(new std::vector<metric_sdk::Record>);
}
/**
* Collects all metrics data from metricsToCollect collection.
*
* @return all metrics in the metricsToCollect snapshot
*/
std::vector<prometheus_client::MetricFamily> PrometheusCollector::Collect() const
{
this->collection_lock_.lock();
if (metrics_to_collect_->empty())
{
this->collection_lock_.unlock();
return {};
}
this->collection_lock_.unlock();
std::vector<prometheus_client::MetricFamily> result;
// copy the intermediate collection, and then clear it
std::vector<metric_sdk::Record> copied_data;
this->collection_lock_.lock();
copied_data = std::vector<metric_sdk::Record>(*metrics_to_collect_);
metrics_to_collect_->clear();
this->collection_lock_.unlock();
result = PrometheusExporterUtils::TranslateToPrometheus(copied_data);
return result;
}
/**
* This function is called by export() function and add the collection of
* records to the metricsToCollect collection
*
* @param records a collection of records to add to the metricsToCollect collection
*/
void PrometheusCollector::AddMetricData(const std::vector<sdk::metrics::Record> &records)
{
if (records.empty())
{
return;
}
collection_lock_.lock();
if (metrics_to_collect_->size() + records.size() <= max_collection_size_)
{
/**
* ValidAggregator is a lambda that checks a Record to see if its
* Aggregator is a valid nostd::shared_ptr and not a nullptr.
*/
auto ValidAggregator = [](sdk::metrics::Record record) {
auto aggregator_variant = record.GetAggregator();
if (nostd::holds_alternative<std::shared_ptr<metric_sdk::Aggregator<int>>>(
aggregator_variant))
{
auto aggregator =
nostd::get<std::shared_ptr<metric_sdk::Aggregator<int>>>(aggregator_variant);
if (!aggregator)
{
return false;
}
}
else if (nostd::holds_alternative<std::shared_ptr<metric_sdk::Aggregator<short>>>(
aggregator_variant))
{
auto aggregator =
nostd::get<std::shared_ptr<metric_sdk::Aggregator<short>>>(aggregator_variant);
if (!aggregator)
{
return false;
}
}
else if (nostd::holds_alternative<std::shared_ptr<metric_sdk::Aggregator<float>>>(
aggregator_variant))
{
auto aggregator =
nostd::get<std::shared_ptr<metric_sdk::Aggregator<float>>>(aggregator_variant);
if (!aggregator)
{
return false;
}
}
else if (nostd::holds_alternative<std::shared_ptr<metric_sdk::Aggregator<double>>>(
aggregator_variant))
{
auto aggregator =
nostd::get<std::shared_ptr<metric_sdk::Aggregator<double>>>(aggregator_variant);
if (!aggregator)
{
return false;
}
}
return true;
};
for (auto &r : records)
{
if (ValidAggregator(r))
{
metrics_to_collect_->emplace_back(r);
}
// Drop the record and write to std::cout
else
{
// Cannot call non const functions on const Record r
sdk::metrics::Record c = r;
std::cout << "Dropped Record containing invalid aggregator with name: " + c.GetName()
<< std::endl;
}
}
}
collection_lock_.unlock();
}
/**
* Get the current collection in the collector.
*
* @return the current metrics_to_collect collection
*/
std::vector<sdk::metrics::Record> PrometheusCollector::GetCollection()
{
return *metrics_to_collect_;
}
/**
* Gets the maximum size of the collection.
*
* @return max collection size
*/
int PrometheusCollector::GetMaxCollectionSize() const
{
return max_collection_size_;
}
} // namespace prometheus
} // namespace exporter
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,110 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
*
* 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.
*/
#ifdef ENABLE_METRICS_PREVIEW
# include "opentelemetry/exporters/prometheus/prometheus_exporter.h"
OPENTELEMETRY_BEGIN_NAMESPACE
namespace exporter
{
namespace prometheus
{
/**
* Constructor - binds an exposer and collector to the exporter
* @param address: an address for an exposer that exposes
* an HTTP endpoint for the exporter to connect to
*/
PrometheusExporter::PrometheusExporter(std::string &address) : is_shutdown_(false)
{
exposer_ = std::unique_ptr<::prometheus::Exposer>(new ::prometheus::Exposer{address});
collector_ = std::shared_ptr<PrometheusCollector>(new PrometheusCollector);
exposer_->RegisterCollectable(collector_);
}
/**
* PrometheusExporter constructor with no parameters
* Used for testing only
*/
PrometheusExporter::PrometheusExporter() : is_shutdown_(false)
{
collector_ = std::unique_ptr<PrometheusCollector>(new PrometheusCollector);
}
/**
* Exports a batch of Metric Records.
* @param records: a collection of records to export
* @return: returns a ReturnCode detailing a success, or type of failure
*/
sdk::common::ExportResult PrometheusExporter::Export(
const std::vector<sdk::metrics::Record> &records) noexcept
{
if (is_shutdown_)
{
return sdk::common::ExportResult::kFailure;
}
else if (records.empty())
{
return sdk::common::ExportResult::kFailureInvalidArgument;
}
else if (collector_->GetCollection().size() + records.size() >
(size_t)collector_->GetMaxCollectionSize())
{
return sdk::common::ExportResult::kFailureFull;
}
else
{
collector_->AddMetricData(records);
return sdk::common::ExportResult::kSuccess;
}
}
/**
* Shuts down the exporter and does cleanup.
* Since Prometheus is a pull based interface,
* we cannot serve data remaining in the intermediate
* collection to to client an HTTP request being sent,
* so we flush the data.
*/
void PrometheusExporter::Shutdown() noexcept
{
is_shutdown_ = true;
collector_->GetCollection().clear();
}
/**
* @return: returns a shared_ptr to
* the PrometheusCollector instance
*/
std::shared_ptr<PrometheusCollector> &PrometheusExporter::GetCollector()
{
return collector_;
}
/**
* @return: Gets the shutdown status of the exporter
*/
bool PrometheusExporter::IsShutdown() const
{
return is_shutdown_;
}
} // namespace prometheus
} // namespace exporter
OPENTELEMETRY_END_NAMESPACE
#endif // ENABLE_METRICS_PREVIEW

View File

@ -1,446 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#ifdef ENABLE_METRICS_PREVIEW
# include <iostream>
# include <sstream>
# include <utility>
# include <vector>
# include "opentelemetry/exporters/prometheus/prometheus_exporter_utils.h"
# include "opentelemetry/sdk/_metrics/aggregator/aggregator.h"
# include "prometheus/metric_type.h"
namespace prometheus_client = ::prometheus;
namespace metric_sdk = opentelemetry::sdk::metrics;
OPENTELEMETRY_BEGIN_NAMESPACE
namespace exporter
{
namespace prometheus
{
/**
* Helper function to convert OpenTelemetry metrics data collection
* to Prometheus metrics data collection
*
* @param records a collection of metrics in OpenTelemetry
* @return a collection of translated metrics that is acceptable by Prometheus
*/
std::vector<prometheus_client::MetricFamily> PrometheusExporterUtils::TranslateToPrometheus(
const std::vector<metric_sdk::Record> &records)
{
if (records.empty())
{
return {};
}
// initialize output vector
std::vector<prometheus_client::MetricFamily> output(records.size());
// iterate through the vector and set result data into it
int i = 0;
for (auto r : records)
{
SetMetricFamily(r, &output[i]);
i++;
}
return output;
}
// ======================= private helper functions =========================
/**
* Set value to metric family according to record
*/
void PrometheusExporterUtils::SetMetricFamily(metric_sdk::Record &record,
prometheus_client::MetricFamily *metric_family)
{
auto origin_name = record.GetName();
auto sanitized = SanitizeNames(origin_name);
metric_family->name = sanitized;
metric_family->help = record.GetDescription();
// unpack the variant and set the metric data to metric family struct
auto agg_var = record.GetAggregator();
auto labels_str = record.GetLabels();
if (nostd::holds_alternative<std::shared_ptr<metric_sdk::Aggregator<int>>>(agg_var))
{
auto aggregator = nostd::get<std::shared_ptr<metric_sdk::Aggregator<int>>>(agg_var);
SetMetricFamilyByAggregator(aggregator, labels_str, metric_family);
}
else if (nostd::holds_alternative<std::shared_ptr<metric_sdk::Aggregator<short>>>(agg_var))
{
auto aggregator = nostd::get<std::shared_ptr<metric_sdk::Aggregator<short>>>(agg_var);
SetMetricFamilyByAggregator(aggregator, labels_str, metric_family);
}
else if (nostd::holds_alternative<std::shared_ptr<metric_sdk::Aggregator<float>>>(
record.GetAggregator()))
{
auto aggregator = nostd::get<std::shared_ptr<metric_sdk::Aggregator<float>>>(agg_var);
SetMetricFamilyByAggregator(aggregator, labels_str, metric_family);
}
else if (nostd::holds_alternative<std::shared_ptr<metric_sdk::Aggregator<double>>>(
record.GetAggregator()))
{
auto aggregator = nostd::get<std::shared_ptr<metric_sdk::Aggregator<double>>>(agg_var);
SetMetricFamilyByAggregator(aggregator, labels_str, metric_family);
}
}
/**
* Sanitize the given metric name or label according to Prometheus rule.
*
* This function is needed because names in OpenTelemetry can contain
* alphanumeric characters, '_', '.', and '-', whereas in Prometheus the
* name should only contain alphanumeric characters and '_'.
*/
std::string PrometheusExporterUtils::SanitizeNames(std::string name)
{
// replace all '.' and '-' with '_'
std::replace(name.begin(), name.end(), '.', '_');
std::replace(name.begin(), name.end(), '-', '_');
return name;
}
/**
* Set value to metric family for different aggregator
*/
template <typename T>
void PrometheusExporterUtils::SetMetricFamilyByAggregator(
std::shared_ptr<metric_sdk::Aggregator<T>> aggregator,
std::string labels_str,
prometheus_client::MetricFamily *metric_family)
{
// get aggregator kind and translate to Prometheus metric type
auto kind = aggregator->get_aggregator_kind();
const prometheus_client::MetricType type = TranslateType(kind);
metric_family->type = type;
// get check-pointed values, label string and check-pointed time
auto checkpointed_values = aggregator->get_checkpoint();
auto time = aggregator->get_checkpoint_timestamp().time_since_epoch();
if (type == prometheus_client::MetricType::Histogram) // Histogram
{
auto boundaries = aggregator->get_boundaries();
auto counts = aggregator->get_counts();
SetData(checkpointed_values, boundaries, counts, labels_str, time, metric_family);
}
else if (type == prometheus_client::MetricType::Summary) // Sketch, Exact
{
std::vector<double> quantile_points = {0, 0.5, 0.9, 0.95, 0.99, 1};
if (kind == metric_sdk::AggregatorKind::Exact)
{
std::vector<T> quantiles;
bool do_quantile = aggregator->get_quant_estimation();
if (do_quantile)
{
quantiles = GetQuantilesVector(aggregator, quantile_points);
}
SetData(checkpointed_values, kind, quantiles, labels_str, time, metric_family, do_quantile,
quantile_points);
}
else if (kind == metric_sdk::AggregatorKind::Sketch)
{
auto quantiles = GetQuantilesVector(aggregator, quantile_points);
SetData(checkpointed_values, kind, quantiles, labels_str, time, metric_family, true,
quantile_points);
}
}
else // Counter, Gauge, MinMaxSumCount, Untyped
{
// Handle MinMaxSumCount: https://github.com/open-telemetry/opentelemetry-cpp/issues/228
// Use sum/count is ok.
if (kind == metric_sdk::AggregatorKind::MinMaxSumCount)
{
double avg = (double)checkpointed_values[2] / checkpointed_values[3];
SetData(avg, labels_str, time, metric_family);
}
else
{
SetData(checkpointed_values, labels_str, type, time, metric_family);
}
}
}
/**
* Translate the OTel metric type to Prometheus metric type
*/
prometheus_client::MetricType PrometheusExporterUtils::TranslateType(
metric_sdk::AggregatorKind kind)
{
switch (kind)
{
case metric_sdk::AggregatorKind::Counter:
return prometheus_client::MetricType::Counter;
case metric_sdk::AggregatorKind::Gauge:
case metric_sdk::AggregatorKind::MinMaxSumCount:
return prometheus_client::MetricType::Gauge;
case metric_sdk::AggregatorKind::Histogram:
return prometheus_client::MetricType::Histogram;
case metric_sdk::AggregatorKind::Sketch:
case metric_sdk::AggregatorKind::Exact:
return prometheus_client::MetricType::Summary;
default:
return prometheus_client::MetricType::Untyped;
}
}
/**
* Set metric data for:
* Counter => Prometheus Counter
* Gauge => Prometheus Gauge
*/
template <typename T>
void PrometheusExporterUtils::SetData(std::vector<T> values,
const std::string &labels,
prometheus_client::MetricType type,
std::chrono::nanoseconds time,
prometheus_client::MetricFamily *metric_family)
{
metric_family->metric.emplace_back();
prometheus_client::ClientMetric &metric = metric_family->metric.back();
SetMetricBasic(metric, time, labels);
SetValue(values, type, &metric);
}
/**
* Set metric data for:
* Histogram => Prometheus Histogram
*/
template <typename T>
void PrometheusExporterUtils::SetData(std::vector<T> values,
const std::vector<double> &boundaries,
const std::vector<int> &counts,
const std::string &labels,
std::chrono::nanoseconds time,
prometheus_client::MetricFamily *metric_family)
{
metric_family->metric.emplace_back();
prometheus_client::ClientMetric &metric = metric_family->metric.back();
SetMetricBasic(metric, time, labels);
SetValue(values, boundaries, counts, &metric);
}
/**
* Set metric data for:
* MinMaxSumCount => Prometheus Gauge
* Use Average (sum / count) as the gauge metric
*/
void PrometheusExporterUtils::SetData(double value,
const std::string &labels,
std::chrono::nanoseconds time,
prometheus_client::MetricFamily *metric_family)
{
metric_family->metric.emplace_back();
prometheus_client::ClientMetric &metric = metric_family->metric.back();
SetMetricBasic(metric, time, labels);
SetValue(value, &metric);
}
/**
* Set metric data for:
* Exact => Prometheus Summary
* Sketch => Prometheus Summary
*/
template <typename T>
void PrometheusExporterUtils::SetData(std::vector<T> values,
metric_sdk::AggregatorKind kind,
const std::vector<T> &quantiles,
const std::string &labels,
std::chrono::nanoseconds time,
prometheus_client::MetricFamily *metric_family,
bool do_quantile,
std::vector<double> quantile_points)
{
metric_family->metric.emplace_back();
prometheus_client::ClientMetric &metric = metric_family->metric.back();
SetMetricBasic(metric, time, labels);
SetValue(values, kind, quantiles, &metric, do_quantile, quantile_points);
}
/**
* Set time and labels to metric data
*/
void PrometheusExporterUtils::SetMetricBasic(prometheus_client::ClientMetric &metric,
std::chrono::nanoseconds time,
const std::string &labels)
{
metric.timestamp_ms = time.count() / 1000000;
auto label_pairs = ParseLabel(labels);
if (!label_pairs.empty())
{
metric.label.resize(label_pairs.size());
for (size_t i = 0; i < label_pairs.size(); ++i)
{
auto origin_name = label_pairs[i].first;
auto sanitized = SanitizeNames(origin_name);
metric.label[i].name = sanitized;
metric.label[i].value = label_pairs[i].second;
}
}
};
/**
* Parse a string of labels (key:value) into a vector of pairs
* {,}
* {l1:v1,l2:v2,...,}
*/
std::vector<std::pair<std::string, std::string>> PrometheusExporterUtils::ParseLabel(
std::string labels)
{
labels = labels.substr(1, labels.size() - 2);
std::vector<std::string> paired_labels;
std::stringstream s_stream(labels);
while (s_stream.good())
{
std::string substr;
getline(s_stream, substr, ','); // get first string delimited by comma
if (!substr.empty())
{
paired_labels.push_back(substr);
}
}
std::vector<std::pair<std::string, std::string>> result;
for (auto &paired : paired_labels)
{
std::size_t split_index = paired.find(':');
std::string label = paired.substr(0, split_index);
std::string value = paired.substr(split_index + 1);
result.emplace_back(std::pair<std::string, std::string>(label, value));
}
return result;
}
/**
* Build a quantiles vector from aggregator
*/
template <typename T>
std::vector<T> PrometheusExporterUtils::GetQuantilesVector(
std::shared_ptr<metric_sdk::Aggregator<T>> aggregator,
const std::vector<double> &quantile_points)
{
std::vector<T> quantiles;
for (double q : quantile_points)
{
T quantile = aggregator->get_quantiles(q);
quantiles.emplace_back(quantile);
}
return quantiles;
}
/**
* Handle Counter and Gauge.
*/
template <typename T>
void PrometheusExporterUtils::SetValue(std::vector<T> values,
prometheus_client::MetricType type,
prometheus_client::ClientMetric *metric)
{
switch (type)
{
case prometheus_client::MetricType::Counter: {
metric->counter.value = values[0];
break;
}
case prometheus_client::MetricType::Gauge: {
metric->gauge.value = values[0];
break;
}
case prometheus_client::MetricType::Untyped: {
metric->untyped.value = values[0];
break;
}
default:
return;
}
}
/**
* Handle Gauge from MinMaxSumCount
*/
void PrometheusExporterUtils::SetValue(double value, prometheus_client::ClientMetric *metric)
{
metric->gauge.value = value;
}
/**
* Handle Histogram
*/
template <typename T>
void PrometheusExporterUtils::SetValue(std::vector<T> values,
std::vector<double> boundaries,
std::vector<int> counts,
prometheus_client::ClientMetric *metric)
{
metric->histogram.sample_sum = values[0];
metric->histogram.sample_count = values[1];
int cumulative = 0;
std::vector<prometheus_client::ClientMetric::Bucket> buckets;
for (size_t i = 0; i < boundaries.size() + 1; i++)
{
prometheus_client::ClientMetric::Bucket bucket;
cumulative += counts[i];
bucket.cumulative_count = cumulative;
if (i != boundaries.size())
{
bucket.upper_bound = boundaries[i];
}
else
{
bucket.upper_bound = std::numeric_limits<double>::infinity();
}
buckets.emplace_back(bucket);
}
metric->histogram.bucket = buckets;
}
/**
* Handle Exact and Sketch
*/
template <typename T>
void PrometheusExporterUtils::SetValue(std::vector<T> values,
metric_sdk::AggregatorKind kind,
std::vector<T> quantiles,
prometheus_client::ClientMetric *metric,
bool do_quantile,
const std::vector<double> &quantile_points)
{
if (kind == metric_sdk::AggregatorKind::Exact)
{
metric->summary.sample_count = values.size();
auto sum = 0;
for (auto val : values)
{
sum += val;
}
metric->summary.sample_sum = sum;
}
else if (kind == metric_sdk::AggregatorKind::Sketch)
{
metric->summary.sample_sum = values[0];
metric->summary.sample_count = values[1];
}
if (do_quantile)
{
std::vector<prometheus_client::ClientMetric::Quantile> prometheus_quantiles;
for (size_t i = 0; i < quantiles.size(); i++)
{
prometheus_client::ClientMetric::Quantile quantile;
quantile.quantile = quantile_points[i];
quantile.value = quantiles[i];
prometheus_quantiles.emplace_back(quantile);
}
metric->summary.quantile = prometheus_quantiles;
}
}
} // namespace prometheus
} // namespace exporter
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -7,7 +7,6 @@
# include <map>
# include <thread>
# include "opentelemetry/_metrics/instrument.h"
# include "opentelemetry/exporters/prometheus/collector.h"
# include "opentelemetry/version.h"
# include "prometheus_test_helper.h"

View File

@ -7,7 +7,6 @@
# include "opentelemetry/exporters/prometheus/collector.h"
# include "opentelemetry/exporters/prometheus/exporter.h"
# include "opentelemetry/sdk/_metrics/aggregator/counter_aggregator.h"
# include "opentelemetry/version.h"
# include "prometheus_test_helper.h"

View File

@ -1,756 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#ifdef ENABLE_METRICS_PREVIEW
# include <gtest/gtest.h>
# include <future>
# include <map>
# include <thread>
# include "opentelemetry/_metrics/instrument.h"
# include "opentelemetry/exporters/prometheus/prometheus_collector.h"
# include "opentelemetry/sdk/_metrics/aggregator/aggregator.h"
# include "opentelemetry/sdk/_metrics/aggregator/counter_aggregator.h"
# include "opentelemetry/sdk/_metrics/aggregator/exact_aggregator.h"
# include "opentelemetry/sdk/_metrics/aggregator/gauge_aggregator.h"
# include "opentelemetry/sdk/_metrics/aggregator/histogram_aggregator.h"
# include "opentelemetry/sdk/_metrics/aggregator/min_max_sum_count_aggregator.h"
# include "opentelemetry/sdk/_metrics/aggregator/sketch_aggregator.h"
# include "opentelemetry/sdk/_metrics/record.h"
# include "opentelemetry/version.h"
using opentelemetry::exporter::prometheus::PrometheusCollector;
namespace metric_api = opentelemetry::metrics;
namespace metric_sdk = opentelemetry::sdk::metrics;
OPENTELEMETRY_BEGIN_NAMESPACE
/**
* CreateAgg() is a helper function that returns a
* nostd::shared_ptr given an AggregatorKind
*/
template <typename T>
std::shared_ptr<metric_sdk::Aggregator<T>> CreateAgg(metric_sdk::AggregatorKind kind,
bool exactMode = true)
{
std::shared_ptr<metric_sdk::Aggregator<T>> aggregator;
switch (kind)
{
case metric_sdk::AggregatorKind::Counter: {
aggregator = std::shared_ptr<metric_sdk::Aggregator<T>>(
new metric_sdk::CounterAggregator<T>(metric_api::InstrumentKind::Counter));
break;
}
case metric_sdk::AggregatorKind::MinMaxSumCount: {
aggregator = std::shared_ptr<metric_sdk::Aggregator<T>>(
new metric_sdk::MinMaxSumCountAggregator<T>(metric_api::InstrumentKind::Counter));
break;
}
case metric_sdk::AggregatorKind::Gauge: {
aggregator = std::shared_ptr<metric_sdk::Aggregator<T>>(
new metric_sdk::GaugeAggregator<T>(metric_api::InstrumentKind::Counter));
break;
}
case metric_sdk::AggregatorKind::Sketch: {
aggregator = std::shared_ptr<metric_sdk::Aggregator<T>>(
new metric_sdk::SketchAggregator<T>(metric_api::InstrumentKind::Counter, 0.000005));
break;
}
case metric_sdk::AggregatorKind::Histogram: {
std::vector<double> boundaries{10, 20};
aggregator = std::shared_ptr<metric_sdk::Aggregator<T>>(
new metric_sdk::HistogramAggregator<T>(metric_api::InstrumentKind::Counter, boundaries));
break;
}
case metric_sdk::AggregatorKind::Exact: {
aggregator = std::shared_ptr<metric_sdk::Aggregator<T>>(
new metric_sdk::ExactAggregator<T>(metric_api::InstrumentKind::Counter, exactMode));
break;
}
default:
aggregator = nullptr;
}
return aggregator;
}
/**
* Populate() updates the aggregator with values and checkpoints it based
* on what its AggregatorKind is
*/
template <typename T>
void Populate(std::shared_ptr<metric_sdk::Aggregator<T>> &aggregator)
{
if (aggregator->get_aggregator_kind() == metric_sdk::AggregatorKind::Counter)
{
aggregator->update(10.0);
aggregator->update(5.0);
aggregator->checkpoint();
}
else if (aggregator->get_aggregator_kind() == metric_sdk::AggregatorKind::MinMaxSumCount)
{
aggregator->update(10);
aggregator->update(2);
aggregator->update(5);
aggregator->checkpoint();
}
else if (aggregator->get_aggregator_kind() == metric_sdk::AggregatorKind::Gauge)
{
aggregator->update(10);
aggregator->update(5);
aggregator->checkpoint();
}
else if (aggregator->get_aggregator_kind() == metric_sdk::AggregatorKind::Sketch)
{
for (double i = 0; i < 10.0; i++)
{
aggregator->update(i);
}
aggregator->checkpoint();
}
else if (aggregator->get_aggregator_kind() == metric_sdk::AggregatorKind::Histogram)
{
for (float i = 0; i < 30.0; i++)
{
aggregator->update(i);
}
aggregator->checkpoint();
}
else if (aggregator->get_aggregator_kind() == metric_sdk::AggregatorKind::Exact)
{
for (double i = 0; i < 10.0; i++)
{
aggregator->update(i);
}
aggregator->checkpoint();
}
}
/**
* Helper function to create a collection of records taken from
* a aggregator of specified AggregatorKind
*/
template <typename T>
std::vector<metric_sdk::Record> CreateRecords(int num,
metric_sdk::AggregatorKind kind,
bool exactMode = true)
{
std::vector<metric_sdk::Record> records;
for (int i = 0; i < num; i++)
{
std::string name = "record-" + std::to_string(i);
std::string description = "record " + std::to_string(i) + " for test purpose";
std::string labels = "{label1:v1,label2:v2,}";
std::shared_ptr<metric_sdk::Aggregator<T>> aggregator = CreateAgg<T>(kind, exactMode);
Populate(aggregator);
metric_sdk::Record r{name, description, labels, aggregator};
records.push_back(r);
}
return records;
}
// ==================== Test for addMetricsData() function ======================
/**
* AddMetricData() should be able to successfully add a collection
* of Records with Counter Aggregators. It checks that the cumulative
* sum of updates to the aggregator of a record before and after AddMetricData()
* is called are equal.
*/
TEST(PrometheusCollector, AddMetricDataWithCounterRecordsSuccessfully)
{
PrometheusCollector collector;
// number of records to create
int num_records = 2;
// construct a collection of records with CounterAggregators and double
std::vector<metric_sdk::Record> records =
CreateRecords<double>(num_records, metric_sdk::AggregatorKind::Counter);
// add records to collection
collector.AddMetricData(records);
// Collection size should be the same as the size
// of the records collection passed to addMetricData()
ASSERT_EQ(collector.GetCollection().size(), records.size());
// check values of records created vs records from metricsToCollect,
// accessed by getCollection()
for (int i = 0; i < num_records; i++)
{
metric_sdk::Record before = records[i];
metric_sdk::Record after = collector.GetCollection()[i];
ASSERT_EQ(before.GetName(), after.GetName());
ASSERT_EQ(before.GetDescription(), after.GetDescription());
ASSERT_EQ(before.GetLabels(), after.GetLabels());
auto before_agg_var = before.GetAggregator();
auto before_agg = nostd::get<std::shared_ptr<metric_sdk::Aggregator<double>>>(before_agg_var);
auto after_agg_var = after.GetAggregator();
auto after_agg = nostd::get<std::shared_ptr<metric_sdk::Aggregator<double>>>(after_agg_var);
ASSERT_EQ(before_agg->get_checkpoint().size(), after_agg->get_checkpoint().size());
for (size_t i = 0; i < before_agg->get_checkpoint().size(); i++)
{
ASSERT_EQ(before_agg->get_checkpoint()[i], after_agg->get_checkpoint()[i]);
}
}
}
/**
* AddMetricData() should be able to successfully add a collection
* of Records with MinMaxSumCount Aggregators. It checks that the min, max,
* sum, and count of updates to the aggregator of a record before and after AddMetricData()
* is called are equal.
*/
TEST(PrometheusCollector, AddMetricDataWithMinMaxSumCountRecordsSuccessfully)
{
PrometheusCollector collector;
// number of records to create
int num_records = 2;
// construct a collection of records with MinMaxSumCountAggregators and short
std::vector<metric_sdk::Record> records =
CreateRecords<short>(num_records, metric_sdk::AggregatorKind::MinMaxSumCount);
// add records to collection
collector.AddMetricData(records);
// Collection size should be the same as the size
// of the records collection passed to addMetricData()
ASSERT_EQ(collector.GetCollection().size(), records.size());
// check values of records created vs records from metricsToCollect,
// accessed by getCollection()
for (int i = 0; i < num_records; i++)
{
metric_sdk::Record before = records[i];
metric_sdk::Record after = collector.GetCollection()[i];
ASSERT_EQ(before.GetName(), after.GetName());
ASSERT_EQ(before.GetDescription(), after.GetDescription());
ASSERT_EQ(before.GetLabels(), after.GetLabels());
auto before_agg_var = before.GetAggregator();
auto before_agg = nostd::get<std::shared_ptr<metric_sdk::Aggregator<short>>>(before_agg_var);
auto after_agg_var = after.GetAggregator();
auto after_agg = nostd::get<std::shared_ptr<metric_sdk::Aggregator<short>>>(after_agg_var);
ASSERT_EQ(before_agg->get_checkpoint().size(), after_agg->get_checkpoint().size());
for (size_t i = 0; i < before_agg->get_checkpoint().size(); i++)
{
ASSERT_EQ(before_agg->get_checkpoint()[i], after_agg->get_checkpoint()[i]);
}
}
}
/**
* AddMetricData() should be able to successfully add a collection
* of Records with Gauge Aggregators. It checks that the last update
* to the aggregator of a record before and after AddMetricData()
* is called are equal.
*/
TEST(PrometheusCollector, AddMetricDataWithGaugeRecordsSuccessfully)
{
PrometheusCollector collector;
// number of records to create
int num_records = 2;
// construct a collection of records with GaugeAggregators and int
std::vector<metric_sdk::Record> records =
CreateRecords<int>(num_records, metric_sdk::AggregatorKind::Gauge);
// add records to collection
collector.AddMetricData(records);
// Collection size should be the same as the size
// of the records collection passed to addMetricData()
ASSERT_EQ(collector.GetCollection().size(), records.size());
// check values of records created vs records from metricsToCollect,
// accessed by getCollection()
for (int i = 0; i < num_records; i++)
{
metric_sdk::Record before = records[i];
metric_sdk::Record after = collector.GetCollection()[i];
ASSERT_EQ(before.GetName(), after.GetName());
ASSERT_EQ(before.GetDescription(), after.GetDescription());
ASSERT_EQ(before.GetLabels(), after.GetLabels());
auto before_agg_var = before.GetAggregator();
auto before_agg = nostd::get<std::shared_ptr<metric_sdk::Aggregator<int>>>(before_agg_var);
auto after_agg_var = after.GetAggregator();
auto after_agg = nostd::get<std::shared_ptr<metric_sdk::Aggregator<int>>>(after_agg_var);
ASSERT_EQ(before_agg->get_checkpoint().size(), after_agg->get_checkpoint().size());
for (size_t i = 0; i < before_agg->get_checkpoint().size(); i++)
{
ASSERT_EQ(before_agg->get_checkpoint()[i], after_agg->get_checkpoint()[i]);
}
}
}
/**
* AddMetricData() should be able to successfully add a collection
* of Records with Sketch Aggregators. It checks that the sum of updates
* and count of values added for a record before and after being added are
* equal using get_checkpoint(). It also checks the same for buckets, in
* get_boundaries(), and counts for buckets, in get_counts().
*/
TEST(PrometheusCollector, AddMetricDataWithSketchRecordsSuccessfully)
{
PrometheusCollector collector;
// number of records to create
int num_records = 2;
// construct a collection of records with SketchAggregators and double
std::vector<metric_sdk::Record> records =
CreateRecords<double>(num_records, metric_sdk::AggregatorKind::Sketch);
// add records to collection
collector.AddMetricData(records);
// Collection size should be the same as the size
// of the records collection passed to addMetricData()
ASSERT_EQ(collector.GetCollection().size(), records.size());
// check values of records created vs records from metricsToCollect,
// accessed by getCollection()
for (int i = 0; i < num_records; i++)
{
metric_sdk::Record before = records[i];
metric_sdk::Record after = collector.GetCollection()[i];
ASSERT_EQ(before.GetName(), after.GetName());
ASSERT_EQ(before.GetDescription(), after.GetDescription());
ASSERT_EQ(before.GetLabels(), after.GetLabels());
auto before_agg_var = before.GetAggregator();
auto before_agg = nostd::get<std::shared_ptr<metric_sdk::Aggregator<double>>>(before_agg_var);
auto after_agg_var = after.GetAggregator();
auto after_agg = nostd::get<std::shared_ptr<metric_sdk::Aggregator<double>>>(after_agg_var);
ASSERT_EQ(before_agg->get_checkpoint().size(), after_agg->get_checkpoint().size());
for (size_t i = 0; i < before_agg->get_checkpoint().size(); i++)
{
ASSERT_EQ(before_agg->get_checkpoint()[i], after_agg->get_checkpoint()[i]);
}
for (size_t i = 0; i < before_agg->get_boundaries().size(); i++)
{
ASSERT_EQ(before_agg->get_boundaries()[i], after_agg->get_boundaries()[i]);
}
for (size_t i = 0; i < before_agg->get_counts().size(); i++)
{
ASSERT_EQ(before_agg->get_counts()[i], after_agg->get_counts()[i]);
}
}
}
/**
* AddMetricData() should be able to successfully add a collection
* of Records with Histogram Aggregators. It checks that the sum of
* updates, number of updates, boundaries, and counts for each bucket
* for the aggregator of a record before and after AddMetricData()
* is called are equal.
*/
TEST(PrometheusCollector, AddMetricDataWithHistogramRecordsSuccessfully)
{
PrometheusCollector collector;
// number of records to create
int num_records = 2;
// construct a collection of records with HistogramAggregators and float
std::vector<metric_sdk::Record> records =
CreateRecords<float>(num_records, metric_sdk::AggregatorKind::Histogram);
// add records to collection
collector.AddMetricData(records);
// Collection size should be the same as the size
// of the records collection passed to addMetricData()
ASSERT_EQ(collector.GetCollection().size(), records.size());
// check values of records created vs records from metricsToCollect,
// accessed by getCollection()
for (int i = 0; i < num_records; i++)
{
metric_sdk::Record before = records[i];
metric_sdk::Record after = collector.GetCollection()[i];
ASSERT_EQ(before.GetName(), after.GetName());
ASSERT_EQ(before.GetDescription(), after.GetDescription());
ASSERT_EQ(before.GetLabels(), after.GetLabels());
auto before_agg_var = before.GetAggregator();
auto before_agg = nostd::get<std::shared_ptr<metric_sdk::Aggregator<float>>>(before_agg_var);
auto after_agg_var = after.GetAggregator();
auto after_agg = nostd::get<std::shared_ptr<metric_sdk::Aggregator<float>>>(after_agg_var);
ASSERT_EQ(before_agg->get_checkpoint().size(), after_agg->get_checkpoint().size());
for (size_t i = 0; i < before_agg->get_checkpoint().size(); i++)
{
ASSERT_EQ(before_agg->get_checkpoint()[i], after_agg->get_checkpoint()[i]);
}
for (size_t i = 0; i < before_agg->get_boundaries().size(); i++)
{
ASSERT_EQ(before_agg->get_boundaries()[i], after_agg->get_boundaries()[i]);
}
for (size_t i = 0; i < before_agg->get_counts().size(); i++)
{
ASSERT_EQ(before_agg->get_counts()[i], after_agg->get_counts()[i]);
}
}
}
/**
* AddMetricData() should be able to successfully add a collection
* of Records with Exact Aggregators. If the Exact Aggregator is in
* quantile mode, it will check quantiles at selected values of 0, 0.25,
* 0.5, 0.75, and 1. If not, it will check the vector of checkpointed
* values in get_checkpoint().
*/
TEST(PrometheusCollector, AddMetricDataWithExactRecordsSuccessfully)
{
PrometheusCollector collector;
// number of records to create
int num_records = 1;
// construct a collection of a single record with a quantile
// estimation ExactAggregator and double
std::vector<metric_sdk::Record> records =
CreateRecords<double>(num_records, metric_sdk::AggregatorKind::Exact, true);
// add records to collection
collector.AddMetricData(records);
// construct a collection of a single record with an in-order
// ExactAggregator and double
records = CreateRecords<double>(num_records, metric_sdk::AggregatorKind::Exact, false);
// add records to collection
collector.AddMetricData(records);
// Collection size should be the same as the size
// of the records collection passed to addMetricData()
ASSERT_EQ(collector.GetCollection().size(), records.size() * 2);
// check values of records created vs records from metricsToCollect,
// accessed by getCollection()
for (int i = 0; i < num_records; i++)
{
metric_sdk::Record before = records[i];
metric_sdk::Record after = collector.GetCollection()[i];
ASSERT_EQ(before.GetName(), after.GetName());
ASSERT_EQ(before.GetDescription(), after.GetDescription());
ASSERT_EQ(before.GetLabels(), after.GetLabels());
auto before_agg_var = before.GetAggregator();
auto before_agg = nostd::get<std::shared_ptr<metric_sdk::Aggregator<double>>>(before_agg_var);
auto after_agg_var = after.GetAggregator();
auto after_agg = nostd::get<std::shared_ptr<metric_sdk::Aggregator<double>>>(after_agg_var);
if (before_agg->get_quant_estimation() && after_agg->get_quant_estimation())
{
for (double i = 0; i <= 1;)
{
ASSERT_EQ(before_agg->get_quantiles(i), after_agg->get_quantiles(i));
i += 0.25;
}
}
else
{
ASSERT_EQ(before_agg->get_checkpoint().size(), after_agg->get_checkpoint().size());
for (size_t i = 0; i < before_agg->get_checkpoint().size(); i++)
{
ASSERT_EQ(before_agg->get_checkpoint()[i], after_agg->get_checkpoint()[i]);
}
}
}
}
TEST(PrometheusCollector, AddMetricDataDoesNotAddWithInsufficentSpace)
{
PrometheusCollector collector;
// number of records to create
int num_records = collector.GetMaxCollectionSize() - 5;
// construct a collection close to max capacity
std::vector<metric_sdk::Record> records =
CreateRecords<double>(num_records, metric_sdk::AggregatorKind::Counter);
collector.AddMetricData(records);
// Check if all the records have been added
ASSERT_EQ(collector.GetCollection().size(), num_records);
// Try adding the same collection of records again to
// metricsToCollect.
collector.AddMetricData(records);
// Check that the number of records in metricsToCollect
// has not changed.
ASSERT_EQ(collector.GetCollection().size(), num_records);
}
TEST(PrometheusCollector, AddMetricDataDoesNotAddBadIndividualRecords)
{
PrometheusCollector collector;
// number of records to create
int num_records = 5;
// construct a collection with the specified number of records
std::vector<metric_sdk::Record> records =
CreateRecords<double>(num_records, metric_sdk::AggregatorKind::Counter);
// add records to collection
collector.AddMetricData(records);
// Check if all the records have been added
ASSERT_EQ(collector.GetCollection().size(), num_records);
// Creates a bad record, with a nullptr aggregator and adds
// it to the colelction of records
std::string name = "bad_record";
std::string description = "nullptr_agg";
std::string labels = "{label1:v1}";
std::shared_ptr<metric_sdk::Aggregator<int>> aggregator;
metric_sdk::Record bad_record{name, description, labels, aggregator};
records.push_back(bad_record);
// add records to collection
collector.AddMetricData(records);
// Check if all the records except the bad
// record have been added; the number of records added
// should be twice the original number of records
// epecified to be created
ASSERT_EQ(collector.GetCollection().size(), num_records * 2);
}
// ==================== Test for Constructor ======================
TEST(PrometheusCollector, ConstructorInitializesCollector)
{
PrometheusCollector collector;
// current size should be 0, capacity should be set to default
ASSERT_EQ(collector.GetCollection().size(), 0);
}
// ==================== Tests for collect() function ======================
/**
* When collector is initialized, the collection inside is should also be initialized
*/
TEST(PrometheusCollector, CollectInitializesMetricFamilyCollection)
{
PrometheusCollector collector;
auto c1 = collector.Collect();
ASSERT_EQ(c1.size(), 0);
}
/**
* Collect function should collect all data and clear the intermediate collection
*/
TEST(PrometheusCollector, CollectClearsTheCollection)
{
PrometheusCollector collector;
// construct a collection to add metric records
int num_records = 2;
auto records = CreateRecords<int>(num_records, metric_sdk::AggregatorKind::Counter);
collector.AddMetricData(records);
// the collection should not be empty now
ASSERT_EQ(collector.GetCollection().size(), num_records);
// don't care the collected result in this test
collector.Collect();
// after the collect() call, the collection should be empty
ASSERT_EQ(collector.GetCollection().size(), 0);
}
/**
* Collected data should be already be parsed to Prometheus Metric format
*/
TEST(PrometheusCollector, CollectParsesDataToMetricFamily)
{
PrometheusCollector collector;
// construct a collection to add metric records
int num_records = 1;
auto records = CreateRecords<int>(num_records, metric_sdk::AggregatorKind::Counter);
collector.AddMetricData(records);
// the collection should not be empty now
ASSERT_EQ(collector.GetCollection().size(), num_records);
auto collected = collector.Collect();
ASSERT_EQ(collected.size(), num_records);
auto metric_family = collected[0];
// Collect function really collects a vector of MetricFamily
ASSERT_EQ(metric_family.name, "record_0");
ASSERT_EQ(metric_family.help, "record 0 for test purpose");
ASSERT_EQ(metric_family.type, prometheus_client::MetricType::Counter);
ASSERT_EQ(metric_family.metric.size(), 1);
ASSERT_DOUBLE_EQ(metric_family.metric[0].counter.value, 15);
}
/**
* Concurrency Test 1: After adding data concurrently, the intermediate collection should
* contain all data from all threads.
*/
TEST(PrometheusCollector, ConcurrencyAddingRecords)
{
PrometheusCollector collector;
// construct a collection to add metric records
int num_records = 2;
std::vector<metric_sdk::Record> records1 =
CreateRecords<int>(num_records, metric_sdk::AggregatorKind::Counter);
std::vector<metric_sdk::Record> records2 =
CreateRecords<int>(num_records, metric_sdk::AggregatorKind::Gauge);
std::thread first(&PrometheusCollector::AddMetricData, std::ref(collector), std::ref(records1));
std::thread second(&PrometheusCollector::AddMetricData, std::ref(collector), std::ref(records2));
first.join();
second.join();
ASSERT_EQ(collector.GetCollection().size(), 4);
}
/**
* Concurrency Test 2: After adding data concurrently and collecting, the intermediate collection
* should be empty, and all data are collected in the result vector.
*/
TEST(PrometheusCollector, ConcurrentlyAddingAndThenCollecting)
{
PrometheusCollector collector;
// construct a collection to add metric records
int num_records = 2;
std::vector<metric_sdk::Record> records1 =
CreateRecords<int>(num_records, metric_sdk::AggregatorKind::Counter);
std::vector<metric_sdk::Record> records2 =
CreateRecords<int>(num_records, metric_sdk::AggregatorKind::Gauge);
std::thread first(&PrometheusCollector::AddMetricData, std::ref(collector), std::ref(records1));
std::thread second(&PrometheusCollector::AddMetricData, std::ref(collector), std::ref(records2));
first.join();
second.join();
auto collect_future = std::async(&PrometheusCollector::Collect, std::ref(collector));
auto res = collect_future.get();
ASSERT_EQ(collector.GetCollection().size(), 0);
ASSERT_EQ(res.size(), 4);
}
/**
* Concurrency Test 3: Concurrently adding and collecting. We don't know when the collect function
* is called, but all data entries are either collected or left in the collection.
*/
TEST(PrometheusCollector, ConcurrentlyAddingAndCollecting)
{
PrometheusCollector collector;
// construct a collection to add metric records
int num_records = 2;
std::vector<metric_sdk::Record> records1 =
CreateRecords<int>(num_records, metric_sdk::AggregatorKind::Counter);
std::vector<metric_sdk::Record> records2 =
CreateRecords<int>(num_records, metric_sdk::AggregatorKind::Gauge);
std::thread first(&PrometheusCollector::AddMetricData, std::ref(collector), std::ref(records1));
std::thread second(&PrometheusCollector::AddMetricData, std::ref(collector), std::ref(records2));
auto collect_future = std::async(&PrometheusCollector::Collect, std::ref(collector));
first.join();
second.join();
auto res = collect_future.get();
// the size of collection can be 0, 2, 4, because we don't know when the collect()
// is really called. However, we claim that if the data in the collection is collected,
// they must be in the res. So res.size() + collection.size() must be the total number
// of data records we generated.
ASSERT_EQ(res.size() + collector.GetCollection().size(), 4);
}
/**
* Concurrency Test 4: Concurrently adding then concurrently collecting. We don't know which
* collecting thread fetches all data, but either one should succeed.
*/
TEST(PrometheusCollector, ConcurrentlyAddingAndConcurrentlyCollecting)
{
PrometheusCollector collector;
// construct a collection to add metric records
int num_records = 2;
std::vector<metric_sdk::Record> records1 =
CreateRecords<int>(num_records, metric_sdk::AggregatorKind::Counter);
std::vector<metric_sdk::Record> records2 =
CreateRecords<int>(num_records, metric_sdk::AggregatorKind::Gauge);
// concurrently adding
std::thread first(&PrometheusCollector::AddMetricData, std::ref(collector), std::ref(records1));
std::thread second(&PrometheusCollector::AddMetricData, std::ref(collector), std::ref(records2));
first.join();
second.join();
// after adding, then concurrently consuming
auto collect_future1 = std::async(&PrometheusCollector::Collect, std::ref(collector));
auto collect_future2 = std::async(&PrometheusCollector::Collect, std::ref(collector));
auto res1 = collect_future1.get();
auto res2 = collect_future2.get();
// all added data must be collected in either res1 or res2
ASSERT_EQ(res1.size() + res2.size(), 4);
}
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,218 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
*
* 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.
*/
#ifdef ENABLE_METRICS_PREVIEW
# include <gtest/gtest.h>
# include <typeinfo>
# include "opentelemetry/exporters/prometheus/prometheus_collector.h"
# include "opentelemetry/exporters/prometheus/prometheus_exporter.h"
# include "opentelemetry/sdk/_metrics/aggregator/counter_aggregator.h"
# include "opentelemetry/version.h"
/**
* PrometheusExporterTest is a friend class of PrometheusExporter.
* It has access to a private constructor that does not take in
* an exposer as an argument, and instead takes no arguments; this
* private constructor is only to be used here for testing
*/
OPENTELEMETRY_BEGIN_NAMESPACE
namespace exporter
{
namespace prometheus
{
class PrometheusExporterTest // : public ::testing::Test
{
public:
PrometheusExporter GetExporter() { return PrometheusExporter(); }
};
} // namespace prometheus
} // namespace exporter
OPENTELEMETRY_END_NAMESPACE
using opentelemetry::exporter::prometheus::PrometheusCollector;
using opentelemetry::exporter::prometheus::PrometheusExporter;
using opentelemetry::exporter::prometheus::PrometheusExporterTest;
using opentelemetry::sdk::common::ExportResult;
using opentelemetry::sdk::metrics::CounterAggregator;
using opentelemetry::sdk::metrics::Record;
/**
* Helper function to create a collection of records taken from
* a counter aggregator
*/
std::vector<Record> CreateRecords(int num)
{
std::vector<Record> records;
for (int i = 0; i < num; i++)
{
std::string name = "record-" + std::to_string(i);
std::string description = "record-" + std::to_string(i);
std::string labels = "record-" + std::to_string(i) + "-label-1.0";
auto aggregator = std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<int>>(
new opentelemetry::sdk::metrics::CounterAggregator<int>(
opentelemetry::metrics::InstrumentKind::Counter));
aggregator->update(10);
aggregator->checkpoint();
Record r{name, description, labels, aggregator};
records.push_back(r);
}
return records;
}
/**
* When a PrometheusExporter is initialized,
* isShutdown should be false.
*/
TEST(PrometheusExporter, InitializeConstructorIsNotShutdown)
{
PrometheusExporterTest p;
PrometheusExporter exporter = p.GetExporter();
// // Asserts that the exporter is not shutdown.
ASSERT_TRUE(!exporter.IsShutdown());
}
/**
* The shutdown() function should set the isShutdown field to true.
*/
TEST(PrometheusExporter, ShutdownSetsIsShutdownToTrue)
{
PrometheusExporterTest p;
PrometheusExporter exporter = p.GetExporter();
// exporter shuold not be shutdown by default
ASSERT_TRUE(!exporter.IsShutdown());
exporter.Shutdown();
// the exporter shuold be shutdown
ASSERT_TRUE(exporter.IsShutdown());
// shutdown function should be idempotent
exporter.Shutdown();
ASSERT_TRUE(exporter.IsShutdown());
}
/**
* The Export() function should return kSuccess = 0
* when data is exported successfully.
*/
TEST(PrometheusExporter, ExportSuccessfully)
{
PrometheusExporterTest p;
PrometheusExporter exporter = p.GetExporter();
int num_records = 2;
std::vector<Record> records = CreateRecords(num_records);
auto res = exporter.Export(records);
// result should be kSuccess = 0
ExportResult code = ExportResult::kSuccess;
ASSERT_EQ(res, code);
}
/**
* If the exporter is shutdown, it cannot process
* any more export requests and returns kFailure = 1.
*/
TEST(PrometheusExporter, ExporterIsShutdown)
{
PrometheusExporterTest p;
PrometheusExporter exporter = p.GetExporter();
int num_records = 1;
std::vector<Record> records = CreateRecords(num_records);
exporter.Shutdown();
// send export request after shutdown
auto res = exporter.Export(records);
// result code should be kFailure = 1
ExportResult code = ExportResult::kFailure;
ASSERT_EQ(res, code);
}
/**
* The Export() function should return
* kFailureFull = 2 when the collection is full,
* or when the collection is not full but does not have enough
* space to hold the batch data.
*/
TEST(PrometheusExporter, CollectionNotEnoughSpace)
{
PrometheusExporterTest p;
PrometheusExporter exporter = p.GetExporter();
int num_records = 2;
// prepare two collections of records to export,
// one close to max size and another one that, when added
// to the first, will exceed the size of the collection
int max_collection_size = exporter.GetCollector()->GetMaxCollectionSize();
std::vector<Record> full_records = CreateRecords(max_collection_size - 1);
std::vector<Record> records = CreateRecords(num_records);
// send export request to fill the
// collection in the collector
auto res = exporter.Export(full_records);
// the result code should be kSuccess = 0
ExportResult code = ExportResult::kSuccess;
ASSERT_EQ(res, code);
// send export request that does not complete
// due to not enough space in the collection
res = exporter.Export(records);
// the result code should be kFailureFull = 2
code = ExportResult::kFailureFull;
ASSERT_EQ(res, code);
}
/**
* The Export() function should return
* kFailureInvalidArgument = 3 when an empty collection
* of records is passed to the Export() function.
*/
TEST(PrometheusExporter, InvalidArgumentWhenPassedEmptyRecordCollection)
{
PrometheusExporterTest p;
PrometheusExporter exporter = p.GetExporter();
// Initializes an empty colelction of records
std::vector<Record> records;
// send export request to fill the
// collection in the collector
auto res = exporter.Export(records);
// the result code should be kFailureInvalidArgument = 3
ExportResult code = ExportResult::kFailureInvalidArgument;
ASSERT_EQ(res, code);
}
#endif // ENABLE_METRICS_PREVIEW

View File

@ -1,460 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#ifdef ENABLE_METRICS_PREVIEW
# include <gtest/gtest.h>
# include <map>
# include <numeric>
# include <string>
# include <typeinfo>
# include <opentelemetry/version.h>
# include "opentelemetry/exporters/prometheus/prometheus_exporter_utils.h"
# include "opentelemetry/sdk/_metrics/aggregator/counter_aggregator.h"
# include "opentelemetry/sdk/_metrics/aggregator/exact_aggregator.h"
# include "opentelemetry/sdk/_metrics/aggregator/gauge_aggregator.h"
# include "opentelemetry/sdk/_metrics/aggregator/histogram_aggregator.h"
# include "opentelemetry/sdk/_metrics/aggregator/min_max_sum_count_aggregator.h"
# include "opentelemetry/sdk/_metrics/aggregator/sketch_aggregator.h"
using opentelemetry::exporter::prometheus::PrometheusExporterUtils;
namespace metric_sdk = opentelemetry::sdk::metrics;
namespace metric_api = opentelemetry::metrics;
namespace prometheus_client = ::prometheus;
OPENTELEMETRY_BEGIN_NAMESPACE
template <typename T>
void assert_basic(prometheus_client::MetricFamily &metric,
const std::string &sanitized_name,
const std::string &description,
prometheus_client::MetricType type,
int label_num,
std::vector<T> vals)
{
ASSERT_EQ(metric.name, sanitized_name); // name sanitized
ASSERT_EQ(metric.help, description); // description not changed
ASSERT_EQ(metric.type, type); // type translated
auto metric_data = metric.metric[0];
ASSERT_EQ(metric_data.label.size(), label_num);
switch (type)
{
case prometheus_client::MetricType::Counter: {
ASSERT_DOUBLE_EQ(metric_data.counter.value, vals[0]);
break;
}
case prometheus_client::MetricType::Gauge: {
ASSERT_EQ(metric_data.gauge.value, vals[0]);
break;
}
case prometheus_client::MetricType::Histogram: {
ASSERT_DOUBLE_EQ(metric_data.histogram.sample_count, vals[0]);
ASSERT_DOUBLE_EQ(metric_data.histogram.sample_sum, vals[1]);
auto buckets = metric_data.histogram.bucket;
ASSERT_EQ(buckets.size(), vals[2]);
break;
}
case prometheus_client::MetricType::Summary: {
ASSERT_DOUBLE_EQ(metric_data.summary.sample_count, vals[0]);
ASSERT_DOUBLE_EQ(metric_data.summary.sample_sum, vals[1]);
break;
}
case prometheus::MetricType::Untyped:
break;
}
}
void assert_histogram(prometheus_client::MetricFamily &metric,
std::vector<double> boundaries,
std::vector<int> correct)
{
int cumulative_count = 0;
auto buckets = metric.metric[0].histogram.bucket;
for (size_t i = 0; i < buckets.size(); i++)
{
auto bucket = buckets[i];
if (i != buckets.size() - 1)
{
ASSERT_DOUBLE_EQ(boundaries[i], bucket.upper_bound);
}
else
{
ASSERT_DOUBLE_EQ(std::numeric_limits<double>::infinity(), bucket.upper_bound);
}
cumulative_count += correct[i];
ASSERT_EQ(cumulative_count, bucket.cumulative_count);
}
}
template <typename T>
metric_sdk::Record get_record(const std::string &type,
int version,
const std::string &label,
std::shared_ptr<metric_sdk::Aggregator<T>> aggregator)
{
std::string name = "test-" + type + "-metric-record-v_" + std::to_string(version) + ".0";
std::string desc = "this is a test " + type + " metric record";
metric_sdk::Record record(name, desc, label, aggregator);
return record;
}
TEST(PrometheusExporterUtils, TranslateToPrometheusEmptyInputReturnsEmptyCollection)
{
std::vector<metric_sdk::Record> collection;
auto translated2 = PrometheusExporterUtils::TranslateToPrometheus(collection);
ASSERT_EQ(translated2.size(), 0);
}
TEST(PrometheusExporterUtils, TranslateToPrometheusIntegerCounter)
{
auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
new metric_sdk::CounterAggregator<int>(metric_api::InstrumentKind::Counter));
std::vector<metric_sdk::Record> collection;
auto record1 = get_record("int-counter", 1, "{label1:v1,label2:v2,label3:v3,}", aggregator);
aggregator->update(10);
aggregator->checkpoint();
collection.emplace_back(record1);
auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
ASSERT_EQ(translated.size(), collection.size());
auto metric1 = translated[0];
std::vector<int> vals = {10};
assert_basic(metric1, "test_int_counter_metric_record_v_1_0", record1.GetDescription(),
prometheus_client::MetricType::Counter, 3, vals);
auto record2 = get_record("int-counter", 2, "{,}", aggregator);
aggregator->update(20);
aggregator->update(30);
aggregator->checkpoint();
collection.emplace_back(record2);
translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
ASSERT_EQ(translated.size(), collection.size());
auto metric2 = translated[1];
vals = {50};
assert_basic(metric2, "test_int_counter_metric_record_v_2_0", record2.GetDescription(),
prometheus_client::MetricType::Counter, 0, vals);
}
TEST(PrometheusExporterUtils, TranslateToPrometheusDoubleCounter)
{
auto aggregator = std::shared_ptr<metric_sdk::Aggregator<double>>(
new metric_sdk::CounterAggregator<double>(metric_api::InstrumentKind::Counter));
std::vector<metric_sdk::Record> collection;
aggregator->update(10.5);
aggregator->checkpoint();
auto record1 = get_record("double-counter", 1, "{label1:v1,label2:v2,label3:v3,}", aggregator);
aggregator->update(22.4);
aggregator->update(31.2);
aggregator->checkpoint();
auto record2 = get_record("double-counter", 2, "{,}", aggregator);
collection.emplace_back(record1);
collection.emplace_back(record2);
auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
ASSERT_EQ(translated.size(), collection.size());
auto metric1 = translated[0];
std::vector<double> vals = {53.6};
assert_basic(metric1, "test_double_counter_metric_record_v_1_0", record1.GetDescription(),
prometheus_client::MetricType::Counter, 3, vals);
auto metric2 = translated[1];
assert_basic(metric2, "test_double_counter_metric_record_v_2_0", record2.GetDescription(),
prometheus_client::MetricType::Counter, 0, vals);
}
TEST(PrometheusExporterUtils, TranslateToPrometheusShortCounter)
{
auto aggregator = std::shared_ptr<metric_sdk::Aggregator<short>>(
new metric_sdk::CounterAggregator<short>(metric_api::InstrumentKind::Counter));
std::vector<metric_sdk::Record> collection;
aggregator->update(10);
aggregator->checkpoint();
auto record1 = get_record("short-counter", 1, "{label1:v1,label2:v2,label3:v3,}", aggregator);
aggregator->update(20);
aggregator->update(30);
aggregator->checkpoint();
auto record2 = get_record("short-counter", 2, "{,}", aggregator);
collection.emplace_back(record1);
collection.emplace_back(record2);
auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
ASSERT_EQ(translated.size(), collection.size());
auto metric1 = translated[0];
std::vector<short> vals = {50};
assert_basic(metric1, "test_short_counter_metric_record_v_1_0", record1.GetDescription(),
prometheus_client::MetricType::Counter, 3, vals);
auto metric2 = translated[1];
assert_basic(metric2, "test_short_counter_metric_record_v_2_0", record2.GetDescription(),
prometheus_client::MetricType::Counter, 0, vals);
}
TEST(PrometheusExporterUtils, TranslateToPrometheusFloatCounter)
{
auto aggregator = std::shared_ptr<metric_sdk::Aggregator<float>>(
new metric_sdk::CounterAggregator<float>(metric_api::InstrumentKind::Counter));
std::vector<metric_sdk::Record> collection;
aggregator->update(10.5f);
aggregator->checkpoint();
auto record1 = get_record("float-counter", 1, "{label1:v1,label2:v2,label3:v3,}", aggregator);
aggregator->update(22.4f);
aggregator->update(31.2f);
aggregator->checkpoint();
auto record2 = get_record("float-counter", 2, "{,}", aggregator);
collection.emplace_back(record1);
collection.emplace_back(record2);
auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
ASSERT_EQ(translated.size(), collection.size());
auto metric1 = translated[0];
std::vector<float> vals = {53.6f};
assert_basic(metric1, "test_float_counter_metric_record_v_1_0", record1.GetDescription(),
prometheus_client::MetricType::Counter, 3, vals);
auto metric2 = translated[1];
assert_basic(metric2, "test_float_counter_metric_record_v_2_0", record2.GetDescription(),
prometheus_client::MetricType::Counter, 0, vals);
}
TEST(PrometheusExporterUtils, TranslateToPrometheusGauge)
{
auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
new metric_sdk::GaugeAggregator<int>(metric_api::InstrumentKind::Counter));
std::vector<metric_sdk::Record> collection;
aggregator->update(10);
aggregator->checkpoint();
auto record1 = get_record("gauge", 1, "{label1:v1,label2:v2,label3:v3,}", aggregator);
aggregator->update(20);
aggregator->update(30);
aggregator->checkpoint();
auto record2 = get_record("gauge", 2, "{,}", aggregator);
collection.emplace_back(record1);
collection.emplace_back(record2);
auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
ASSERT_EQ(translated.size(), collection.size());
auto metric1 = translated[0];
std::vector<int> vals = {30};
assert_basic(metric1, "test_gauge_metric_record_v_1_0", record1.GetDescription(),
prometheus_client::MetricType::Gauge, 3, vals);
auto metric2 = translated[1];
assert_basic(metric2, "test_gauge_metric_record_v_2_0", record2.GetDescription(),
prometheus_client::MetricType::Gauge, 0, vals);
}
TEST(PrometheusExporterUtils, TranslateToPrometheusHistogramUniform)
{
std::vector<double> boundaries{10, 20, 30, 40, 50};
auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
new metric_sdk::HistogramAggregator<int>(metric_api::InstrumentKind::Counter, boundaries));
std::vector<metric_sdk::Record> collection;
auto record = get_record("histogram-uniform", 1, "{label1:v1,label2:v2,label3:v3,}", aggregator);
int count_num = 60;
for (int i = 0; i < count_num; i++)
{
aggregator->update(i);
}
aggregator->checkpoint();
collection.emplace_back(record);
auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
ASSERT_EQ(translated.size(), collection.size());
auto metric = translated[0];
std::vector<int> vals = {aggregator->get_checkpoint()[1], aggregator->get_checkpoint()[0],
(int)boundaries.size() + 1};
assert_basic(metric, "test_histogram_uniform_metric_record_v_1_0", record.GetDescription(),
prometheus_client::MetricType::Histogram, 3, vals);
std::vector<int> correct = aggregator->get_counts();
assert_histogram(metric, boundaries, correct);
}
TEST(PrometheusExporterUtils, TranslateToPrometheusHistogramNormal)
{
std::vector<double> boundaries{2, 4, 6, 8, 10, 12};
auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
new metric_sdk::HistogramAggregator<int>(metric_api::InstrumentKind::Counter, boundaries));
std::vector<metric_sdk::Record> collection;
auto record = get_record("histogram-normal", 1, "{label1:v1,label2:v2,label3:v3,}", aggregator);
std::vector<int> values{1, 3, 3, 5, 5, 5, 7, 7, 7, 7, 9, 9, 9, 11, 11, 13};
for (int i : values)
{
aggregator->update(i);
}
aggregator->checkpoint();
collection.emplace_back(record);
auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
ASSERT_EQ(translated.size(), collection.size());
auto metric = translated[0];
std::vector<int> vals = {aggregator->get_checkpoint()[1], aggregator->get_checkpoint()[0],
(int)boundaries.size() + 1};
assert_basic(metric, "test_histogram_normal_metric_record_v_1_0", record.GetDescription(),
prometheus_client::MetricType::Histogram, 3, vals);
std::vector<int> correct = aggregator->get_counts();
assert_histogram(metric, boundaries, correct);
}
TEST(PrometheusExporterUtils, TranslateToPrometheusExact)
{
auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
new metric_sdk::ExactAggregator<int>(metric_api::InstrumentKind::Counter, true));
std::vector<metric_sdk::Record> collection;
int count_num = 100;
for (int i = 0; i <= count_num; i++)
{
aggregator->update(i);
}
aggregator->checkpoint();
auto record = get_record("exact", 1, "{label-1:v1,label_2:v2,label3:v3,}", aggregator);
collection.emplace_back(record);
auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
ASSERT_EQ(translated.size(), collection.size());
auto metric = translated[0];
std::vector<int> vals = {101, 5050};
assert_basic(metric, "test_exact_metric_record_v_1_0", record.GetDescription(),
prometheus_client::MetricType::Summary, 3, vals);
auto quantile = metric.metric[0].summary.quantile;
ASSERT_EQ(quantile.size(), 6);
ASSERT_DOUBLE_EQ(quantile[0].value, 0);
ASSERT_DOUBLE_EQ(quantile[1].value, 50);
ASSERT_DOUBLE_EQ(quantile[2].value, 90);
ASSERT_DOUBLE_EQ(quantile[3].value, 95);
ASSERT_DOUBLE_EQ(quantile[4].value, 99);
ASSERT_DOUBLE_EQ(quantile[5].value, 100);
}
TEST(PrometheusExporterUtils, TranslateToPrometheusExactNoQuantile)
{
auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
new metric_sdk::ExactAggregator<int>(metric_api::InstrumentKind::Counter, false));
std::vector<metric_sdk::Record> collection;
int count_num = 10;
for (int i = 0; i < count_num; i++)
{
aggregator->update(i);
}
aggregator->checkpoint();
auto record = get_record("exact-no-quantile", 1, "{label1:v1,label2:v2,}", aggregator);
collection.emplace_back(record);
auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
ASSERT_EQ(translated.size(), collection.size());
auto metric = translated[0];
std::vector<int> vals = {count_num, 45};
assert_basic(metric, "test_exact_no_quantile_metric_record_v_1_0", record.GetDescription(),
prometheus_client::MetricType::Summary, 2, vals);
auto quantile = metric.metric[0].summary.quantile;
ASSERT_EQ(quantile.size(), 0);
}
TEST(PrometheusExporterUtils, TranslateToPrometheusMinMaxSumCount)
{
auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
new metric_sdk::MinMaxSumCountAggregator<int>(metric_api::InstrumentKind::Counter));
std::vector<metric_sdk::Record> collection;
// min: 1, max: 10, sum: 55, count: 10
for (int i = 1; i <= 10; i++)
{
aggregator->update(i);
}
aggregator->checkpoint();
auto record = get_record("mmsc", 1, "{label1:v1,label2:v2,label3:v3,}", aggregator);
collection.emplace_back(record);
auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
ASSERT_EQ(translated.size(), collection.size());
auto metric = translated[0];
// in this version of implementation, we use the sum/count as a gauge
std::vector<double> vals = {5.5};
assert_basic(metric, "test_mmsc_metric_record_v_1_0", record.GetDescription(),
prometheus_client::MetricType::Gauge, 3, vals);
}
TEST(PrometheusExporterUtils, TranslateToPrometheusSketch)
{
auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
new metric_sdk::SketchAggregator<int>(metric_api::InstrumentKind::Counter, 0.0005));
std::vector<metric_sdk::Record> collection;
for (int i = 0; i <= 100; i++)
{
aggregator->update(i);
}
aggregator->checkpoint();
auto record = get_record("sketch", 1, "{label1:v1,label2:v2,}", aggregator);
collection.emplace_back(record);
auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
ASSERT_EQ(translated.size(), collection.size());
auto metric = translated[0];
std::vector<int> vals = {aggregator->get_checkpoint()[1], aggregator->get_checkpoint()[0]};
assert_basic(metric, "test_sketch_metric_record_v_1_0", record.GetDescription(),
prometheus_client::MetricType::Summary, 2, vals);
auto quantile = metric.metric[0].summary.quantile;
ASSERT_EQ(quantile.size(), 6);
ASSERT_DOUBLE_EQ(quantile[0].value, 0);
ASSERT_DOUBLE_EQ(quantile[1].value, 49);
ASSERT_DOUBLE_EQ(quantile[2].value, 89);
ASSERT_DOUBLE_EQ(quantile[3].value, 94);
ASSERT_DOUBLE_EQ(quantile[4].value, 98);
ASSERT_DOUBLE_EQ(quantile[5].value, 99);
}
TEST(PrometheusExporterUtils, TranslateToPrometheusMultipleAggregators)
{
auto counter_aggregator = std::shared_ptr<metric_sdk::Aggregator<double>>(
new metric_sdk::CounterAggregator<double>(metric_api::InstrumentKind::Counter));
auto gauge_aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
new metric_sdk::GaugeAggregator<int>(metric_api::InstrumentKind::Counter));
std::vector<metric_sdk::Record> collection;
counter_aggregator->update(10);
counter_aggregator->update(20);
counter_aggregator->checkpoint();
auto record1 = get_record("counter", 1, "{label1:v1,label2:v2,label3:v3,}", counter_aggregator);
gauge_aggregator->update(10);
gauge_aggregator->update(30);
gauge_aggregator->update(20);
gauge_aggregator->checkpoint();
auto record2 = get_record("gauge", 1, "{label1:v1,}", gauge_aggregator);
collection.emplace_back(record1);
collection.emplace_back(record2);
auto translated = PrometheusExporterUtils::TranslateToPrometheus(collection);
ASSERT_EQ(translated.size(), collection.size());
auto metric1 = translated[0];
std::vector<int> vals = {30};
assert_basic(metric1, "test_counter_metric_record_v_1_0", record1.GetDescription(),
prometheus_client::MetricType::Counter, 3, vals);
auto metric2 = translated[1];
vals = {20};
assert_basic(metric2, "test_gauge_metric_record_v_1_0", record2.GetDescription(),
prometheus_client::MetricType::Gauge, 1, vals);
}
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,156 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef ENABLE_METRICS_PREVIEW
# include <mutex>
# include <vector>
# include "opentelemetry/_metrics/instrument.h"
# include "opentelemetry/common/timestamp.h"
# include "opentelemetry/version.h"
OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace metrics
{
enum class AggregatorKind
{
Counter = 0,
MinMaxSumCount = 1,
Gauge = 2,
Sketch = 3,
Histogram = 4,
Exact = 5,
};
/*
* Performs calculations necessary to combine updates from instruments into an
* insightful value.
* Also stores current instrument values and checkpoints collected at intervals
* governing the entire pipeline.
*/
template <typename T>
class Aggregator
{
public:
Aggregator() = default;
virtual ~Aggregator() = default;
/**
* Receives a captured value from the instrument and applies it to the current aggregator value.
*
* @param val, the raw value used in aggregation
* @return none
*/
virtual void update(T val) = 0;
/**
* Checkpoints the current value. This function will overwrite the current checkpoint with the
* current value.
*
* @param none
* @return none
*/
virtual void checkpoint() = 0;
/**
* Merges the values of two aggregators in a semantically accurate manner.
* Merging will occur differently for different aggregators depending on the
* way values are tracked.
*
* @param other, the aggregator with merge with
* @return none
*/
void merge(Aggregator *other);
/**
* Returns the checkpointed value
*
* @param none
* @return the value of the checkpoint
*/
virtual std::vector<T> get_checkpoint() = 0;
/**
* Returns the current value
*
* @param none
* @return the present aggregator value
*/
virtual std::vector<T> get_values() = 0;
/**
* Returns the instrument kind which this aggregator is associated with
*
* @param none
* @return the InstrumentKind of the aggregator's owner
*/
virtual opentelemetry::metrics::InstrumentKind get_instrument_kind() final { return kind_; }
/**
* Returns the type of this aggregator
*
* @param none
* @return the AggregatorKind of this instrument
*/
virtual AggregatorKind get_aggregator_kind() final { return agg_kind_; }
/**
* Getter function for updated_ protected var
*
* @return A bool indicating wether or not this aggregator has been updated
* in the most recent collection interval.
*/
virtual bool is_updated() final { return updated_; }
// virtual function to be overridden for the Histogram Aggregator
virtual std::vector<double> get_boundaries() { return std::vector<double>(); }
// virtual function to be overridden for the Histogram Aggregator
virtual std::vector<int> get_counts() { return std::vector<int>(); }
// virtual function to be overridden for Exact and Sketch Aggregators
virtual bool get_quant_estimation() { return false; }
// virtual function to be overridden for Exact and Sketch Aggregators
virtual T get_quantiles(double q) { return values_[0]; }
// virtual function to be overridden for Sketch Aggregator
virtual double get_error_bound() { return 0; }
// virtual function to be overridden for Sketch Aggregator
virtual size_t get_max_buckets() { return 0; }
// virtual function to be overridden for Gauge Aggregator
virtual opentelemetry::common::SystemTimestamp get_checkpoint_timestamp()
{
return opentelemetry::common::SystemTimestamp();
}
// Custom copy constructor to handle the mutex
Aggregator(const Aggregator &cp)
{
values_ = cp.values_;
checkpoint_ = cp.checkpoint_;
kind_ = cp.kind_;
agg_kind_ = cp.agg_kind_;
// use default initialized mutex as they cannot be copied
}
protected:
std::vector<T> values_;
std::vector<T> checkpoint_;
opentelemetry::metrics::InstrumentKind kind_;
std::mutex mu_;
AggregatorKind agg_kind_;
bool updated_;
};
} // namespace metrics
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,108 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef ENABLE_METRICS_PREVIEW
# include <mutex>
# include <vector>
# include "opentelemetry/_metrics/instrument.h"
# include "opentelemetry/sdk/_metrics/aggregator/aggregator.h"
# include "opentelemetry/version.h"
OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace metrics
{
template <class T>
class CounterAggregator final : public Aggregator<T>
{
public:
CounterAggregator(opentelemetry::metrics::InstrumentKind kind)
{
this->kind_ = kind;
this->values_ = std::vector<T>(1, 0);
this->checkpoint_ = std::vector<T>(1, 0);
this->agg_kind_ = AggregatorKind::Counter;
}
/**
* Receives a captured value from the instrument and applies it to the current aggregator value.
*
* @param val, the raw value used in aggregation
* @return none
*/
void update(T val) override
{
this->mu_.lock();
this->updated_ = true;
this->values_[0] += val; // atomic operation
this->mu_.unlock();
}
/**
* Checkpoints the current value. This function will overwrite the current checkpoint with the
* current value.
*
* @param none
* @return none
*/
void checkpoint() override
{
this->mu_.lock();
this->updated_ = false;
this->checkpoint_ = this->values_;
this->values_[0] = 0;
this->mu_.unlock();
}
/**
* Merges the values of two aggregators in a semantically accurate manner.
* In this case, merging only requires the the current values of the two aggregators be summed.
*
* @param other, the aggregator with merge with
* @return none
*/
void merge(CounterAggregator other)
{
if (this->agg_kind_ == other.agg_kind_)
{
this->mu_.lock();
this->values_[0] += other.values_[0];
this->checkpoint_[0] += other.checkpoint_[0];
this->mu_.unlock();
}
else
{
# if __EXCEPTIONS
throw std::invalid_argument("Aggregators of different types cannot be merged.");
# else
std::terminate();
# endif
}
}
/**
* Returns the checkpointed value
*
* @param none
* @return the value of the checkpoint
*/
virtual std::vector<T> get_checkpoint() override { return this->checkpoint_; }
/**
* Returns the current values
*
* @param none
* @return the present aggregator values
*/
virtual std::vector<T> get_values() override { return this->values_; }
};
} // namespace metrics
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,169 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef ENABLE_METRICS_PREVIEW
# include "opentelemetry/_metrics/instrument.h"
# include "opentelemetry/sdk/_metrics/aggregator/aggregator.h"
# include "opentelemetry/version.h"
# include <cmath>
# include <memory>
# include <mutex>
# include <vector>
OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace metrics
{
/**
* This aggregator has two modes. In-order and quantile estimation.
*
* The first mode simply stores all values sent to the Update()
* function in a vector and maintains the order they were sent in.
*
* The second mode also stores all values sent to the Update()
* function in a vector but sorts this vector when Checkpoint()
* is called. This mode also includes a function, Quantile(),
* that estimates the quantiles of the recorded data.
*
* @tparam T the type of values stored in this aggregator.
*/
template <class T>
class ExactAggregator : public Aggregator<T>
{
public:
ExactAggregator(opentelemetry::metrics::InstrumentKind kind, bool quant_estimation = false)
{
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
this->kind_ = kind;
this->checkpoint_ = this->values_;
this->agg_kind_ = AggregatorKind::Exact;
quant_estimation_ = quant_estimation;
}
~ExactAggregator() = default;
ExactAggregator(const ExactAggregator &cp)
{
this->values_ = cp.values_;
this->checkpoint_ = cp.checkpoint_;
this->kind_ = cp.kind_;
this->agg_kind_ = cp.agg_kind_;
quant_estimation_ = cp.quant_estimation_;
// use default initialized mutex as they cannot be copied
}
/**
* Receives a captured value from the instrument and adds it to the values_ vector.
*
* @param val, the raw value used in aggregation
*/
void update(T val) override
{
this->mu_.lock();
this->updated_ = true;
this->values_.push_back(val);
this->mu_.unlock();
}
/**
* Checkpoints the current values. This function will overwrite the current checkpoint with the
* current value. Sorts the values_ vector if quant_estimation_ == true
*
*/
void checkpoint() override
{
this->mu_.lock();
this->updated_ = false;
if (quant_estimation_)
{
std::sort(this->values_.begin(), this->values_.end());
}
this->checkpoint_ = this->values_;
this->values_.clear();
this->mu_.unlock();
}
/**
* Merges two exact aggregators' values_ vectors together.
*
* @param other the aggregator to merge with this aggregator
*/
void merge(const ExactAggregator &other)
{
if (this->kind_ == other.kind_)
{
this->mu_.lock();
// First merge values
this->values_.insert(this->values_.end(), other.values_.begin(), other.values_.end());
// Now merge checkpoints
this->checkpoint_.insert(this->checkpoint_.end(), other.checkpoint_.begin(),
other.checkpoint_.end());
this->mu_.unlock();
}
else
{
// Log error
return;
}
}
/**
* Performs quantile estimation on the checkpoint vector in this aggregator.
* This function only works if quant_estimation_ == true.
* @param q the quantile to estimate. 0 <= q <= 1
* @return the nearest value in the vector to the exact quantile.
*/
T get_quantiles(double q) override
{
if (!quant_estimation_)
{
// Log error
# if __EXCEPTIONS
throw std::domain_error("Exact aggregator is not in quantile estimation mode!");
# else
std::terminate();
# endif
}
if (this->checkpoint_.size() == 0 || q < 0 || q > 1)
{
// Log error
# if __EXCEPTIONS
throw std::invalid_argument("Arg 'q' must be between 0 and 1, inclusive");
# else
std::terminate();
# endif
}
else if (q == 0 || this->checkpoint_.size() == 1)
{
return this->checkpoint_[0];
}
else if (q == 1)
{
return this->checkpoint_[this->checkpoint_.size() - 1];
}
else
{
float position = float(float(this->checkpoint_.size() - 1) * q);
int ceiling = int(ceil(position));
return this->checkpoint_[ceiling];
}
}
//////////////////////////ACCESSOR FUNCTIONS//////////////////////////
std::vector<T> get_checkpoint() override { return this->checkpoint_; }
std::vector<T> get_values() override { return this->values_; }
bool get_quant_estimation() override { return quant_estimation_; }
private:
bool quant_estimation_; // Used to switch between in-order and quantile estimation modes
};
} // namespace metrics
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,146 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef ENABLE_METRICS_PREVIEW
# include "opentelemetry/_metrics/instrument.h"
# include "opentelemetry/common/timestamp.h"
# include "opentelemetry/sdk/_metrics/aggregator/aggregator.h"
# include "opentelemetry/version.h"
# include <memory>
# include <mutex>
# include <vector>
OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace metrics
{
/**
* This aggregator stores and maintains a vector of
* type T where the contents of the vector simply
* include the last value recorded to the aggregator.
* The aggregator also maintains a timestamp of when
* the last value was recorded.
*
* @tparam T the type of values stored in this aggregator.
*/
template <class T>
class GaugeAggregator : public Aggregator<T>
{
public:
explicit GaugeAggregator(opentelemetry::metrics::InstrumentKind kind)
{
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
this->kind_ = kind;
this->values_ = std::vector<T>(1, 0);
this->checkpoint_ = this->values_;
this->agg_kind_ = AggregatorKind::Gauge;
current_timestamp_ = opentelemetry::common::SystemTimestamp(std::chrono::system_clock::now());
}
~GaugeAggregator() = default;
GaugeAggregator(const GaugeAggregator &cp)
{
this->values_ = cp.values_;
this->checkpoint_ = cp.checkpoint_;
this->kind_ = cp.kind_;
this->agg_kind_ = cp.agg_kind_;
current_timestamp_ = cp.current_timestamp_;
// use default initialized mutex as they cannot be copied
}
/**
* Receives a captured value from the instrument and applies it to the current aggregator value.
*
* @param val, the raw value used in aggregation
*/
void update(T val) override
{
this->mu_.lock();
this->updated_ = true;
this->values_[0] = val;
current_timestamp_ = opentelemetry::common::SystemTimestamp(std::chrono::system_clock::now());
this->mu_.unlock();
}
/**
* Checkpoints the current value. This function will overwrite the current checkpoint with the
* current value.
*
* @return none
*/
void checkpoint() override
{
this->mu_.lock();
this->updated_ = false;
this->checkpoint_ = this->values_;
// Reset the values to default
this->values_[0] = 0;
checkpoint_timestamp_ = current_timestamp_;
current_timestamp_ = opentelemetry::common::SystemTimestamp(std::chrono::system_clock::now());
this->mu_.unlock();
}
/**
* Merges two Gauge aggregators together
*
* @param other the aggregator to merge with this aggregator
*/
void merge(GaugeAggregator<T> other)
{
if (this->kind_ == other.kind_)
{
this->mu_.lock();
// First merge values
this->values_[0] = other.values_[0];
// Now merge checkpoints
this->checkpoint_[0] = other.checkpoint_[0];
current_timestamp_ = opentelemetry::common::SystemTimestamp(std::chrono::system_clock::now());
this->mu_.unlock();
}
else
{
// Log error
return;
}
}
/**
* @return the value of the latest checkpoint
*/
std::vector<T> get_checkpoint() override { return this->checkpoint_; }
/**
* @return the latest checkpointed timestamp
*/
opentelemetry::common::SystemTimestamp get_checkpoint_timestamp() override
{
return checkpoint_timestamp_;
}
/**
* @return the values_ vector stored in this aggregator
*/
std::vector<T> get_values() override { return this->values_; }
/**
* @return the timestamp of when the last value recorded
*/
opentelemetry::common::SystemTimestamp get_timestamp() { return current_timestamp_; }
private:
opentelemetry::common::SystemTimestamp current_timestamp_;
opentelemetry::common::SystemTimestamp checkpoint_timestamp_;
};
} // namespace metrics
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,207 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef ENABLE_METRICS_PREVIEW
# include <algorithm>
# include <mutex>
# include <stdexcept>
# include <vector>
# include "opentelemetry/_metrics/instrument.h"
# include "opentelemetry/sdk/_metrics/aggregator/aggregator.h"
# include "opentelemetry/version.h"
OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace metrics
{
template <class T>
class HistogramAggregator final : public Aggregator<T>
{
public:
/**
* Constructor for the histogram aggregator. A sorted vector of boundaries is expected and
* boundaries are doubles regardless of the aggregator's templated data type.
*
* Sum is stored in values_[0]
* Count is stored in position_[1]
*/
HistogramAggregator(opentelemetry::metrics::InstrumentKind kind, std::vector<double> boundaries)
{
if (!std::is_sorted(boundaries.begin(), boundaries.end()))
{
# if __EXCEPTIONS
throw std::invalid_argument("Histogram boundaries must be monotonic.");
# else
std::terminate();
# endif
}
this->kind_ = kind;
this->agg_kind_ = AggregatorKind::Histogram;
boundaries_ = boundaries;
this->values_ = std::vector<T>(2, 0);
this->checkpoint_ = std::vector<T>(2, 0);
bucketCounts_ = std::vector<int>(boundaries_.size() + 1, 0);
bucketCounts_ckpt_ = std::vector<int>(boundaries_.size() + 1, 0);
}
/**
* Receives a captured value from the instrument and inserts it into the current histogram counts.
*
* Depending on the use case, a linear search or binary search based implementation may be
* preferred. In uniformly distributed datasets, linear search outperforms binary search until 512
* buckets. However, if the distribution is strongly skewed right (for example server latency
* where most values may be <10ms but the range is from 0 - 1000 ms), a linear search could be
* superior even with more than 500 buckets as almost all values inserted would be at the
* beginning of the boundaries array and thus found more quickly through linear search.
*
* @param val, the raw value used in aggregation
* @return none
*/
void update(T val) override
{
this->mu_.lock();
this->updated_ = true;
size_t bucketID = boundaries_.size();
for (size_t i = 0; i < boundaries_.size(); i++)
{
if (val < boundaries_[i]) // concurrent read is thread-safe
{
bucketID = i;
break;
}
}
// Alternate implementation with binary search
// auto pos = std::lower_bound (boundaries_.begin(), boundaries_.end(), val);
// bucketCounts_[pos-boundaries_.begin()] += 1;
this->values_[0] += val;
this->values_[1] += 1;
bucketCounts_[bucketID] += 1;
this->mu_.unlock();
}
/**
* Checkpoints the current value. This function will overwrite the current checkpoint with the
* current value.
*
* @param none
* @return none
*/
void checkpoint() override
{
this->mu_.lock();
this->updated_ = false;
this->checkpoint_ = this->values_;
this->values_[0] = 0;
this->values_[1] = 0;
bucketCounts_ckpt_ = bucketCounts_;
std::fill(bucketCounts_.begin(), bucketCounts_.end(), 0);
this->mu_.unlock();
}
/**
* Merges the values of two aggregators in a semantically accurate manner.
* A histogram aggregator can only be merged with another histogram aggregator that has the same
* boudnaries. A histogram merge first adds the sum and count values then iterates over the adds
* the bucket counts element by element.
*
* @param other, the aggregator with merge with
* @return none
*/
void merge(HistogramAggregator other)
{
this->mu_.lock();
// Ensure that incorrect types are not merged
if (this->agg_kind_ != other.agg_kind_)
{
# if __EXCEPTIONS
throw std::invalid_argument("Aggregators of different types cannot be merged.");
# else
std::terminate();
# endif
// Reject histogram merges with differing boundary vectors
}
else if (other.boundaries_ != this->boundaries_)
{
# if __EXCEPTIONS
throw std::invalid_argument("Histogram boundaries do not match.");
# else
std::terminate();
# endif
}
this->values_[0] += other.values_[0];
this->values_[1] += other.values_[1];
this->checkpoint_[0] += other.checkpoint_[0];
this->checkpoint_[1] += other.checkpoint_[1];
for (size_t i = 0; i < bucketCounts_.size(); i++)
{
bucketCounts_[i] += other.bucketCounts_[i];
bucketCounts_ckpt_[i] += other.bucketCounts_ckpt_[i];
}
this->mu_.unlock();
}
/**
* Returns the checkpointed value
*
* @param none
* @return the value of the checkpoint
*/
std::vector<T> get_checkpoint() override { return this->checkpoint_; }
/**
* Returns the current values
*
* @param none
* @return the present aggregator values
*/
std::vector<T> get_values() override { return this->values_; }
/**
* Returns the bucket boundaries specified at this aggregator's creation.
*
* @param none
* @return the aggregator boundaries
*/
virtual std::vector<double> get_boundaries() override { return boundaries_; }
/**
* Returns the current counts for each bucket .
*
* @param none
* @return the aggregator bucket counts
*/
virtual std::vector<int> get_counts() override { return bucketCounts_ckpt_; }
HistogramAggregator(const HistogramAggregator &cp)
{
this->values_ = cp.values_;
this->checkpoint_ = cp.checkpoint_;
this->kind_ = cp.kind_;
this->agg_kind_ = cp.agg_kind_;
boundaries_ = cp.boundaries_;
bucketCounts_ = cp.bucketCounts_;
bucketCounts_ckpt_ = cp.bucketCounts_ckpt_;
// use default initialized mutex as they cannot be copied
}
private:
std::vector<double> boundaries_;
std::vector<int> bucketCounts_;
std::vector<int> bucketCounts_ckpt_;
};
} // namespace metrics
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,159 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef ENABLE_METRICS_PREVIEW
# include "opentelemetry/_metrics/instrument.h"
# include "opentelemetry/sdk/_metrics/aggregator/aggregator.h"
# include "opentelemetry/version.h"
# include <memory>
# include <mutex>
# include <vector>
OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace metrics
{
const int MinValueIndex = 0;
const int MaxValueIndex = 1;
const int SumValueIndex = 2;
const int CountValueIndex = 3;
/**
* This aggregator stores and maintains a vector of
* type T where the contents in the vector are made
* up of the minimum value recorded to this instrument,
* the maximum value, the sum of all values, and the
* count of all values.
*
* @tparam T the type of values stored in this aggregator.
*/
template <class T>
class MinMaxSumCountAggregator : public Aggregator<T>
{
public:
explicit MinMaxSumCountAggregator(opentelemetry::metrics::InstrumentKind kind)
{
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
this->kind_ = kind;
this->values_ = std::vector<T>(4, 0); // {min, max, sum, count}
this->checkpoint_ = this->values_;
this->agg_kind_ = AggregatorKind::MinMaxSumCount;
}
~MinMaxSumCountAggregator() = default;
MinMaxSumCountAggregator(const MinMaxSumCountAggregator &cp)
{
this->values_ = cp.values_;
this->checkpoint_ = cp.checkpoint_;
this->kind_ = cp.kind_;
this->agg_kind_ = cp.agg_kind_;
// use default initialized mutex as they cannot be copied
}
/**
* Receives a captured value from the instrument and applies it to the current aggregator value.
*
* @param val, the raw value used in aggregation
*/
void update(T val) override
{
this->mu_.lock();
this->updated_ = true;
if (this->values_[CountValueIndex] == 0 || val < this->values_[MinValueIndex]) // set min
this->values_[MinValueIndex] = val;
if (this->values_[CountValueIndex] == 0 || val > this->values_[MaxValueIndex]) // set max
this->values_[MaxValueIndex] = val;
this->values_[SumValueIndex] += val; // compute sum
this->values_[CountValueIndex]++; // increment count
this->mu_.unlock();
}
/**
* Checkpoints the current value. This function will overwrite the current checkpoint with the
* current value.
*
*/
void checkpoint() override
{
this->mu_.lock();
this->updated_ = false;
this->checkpoint_ = this->values_;
// Reset the values
this->values_[MinValueIndex] = 0;
this->values_[MaxValueIndex] = 0;
this->values_[SumValueIndex] = 0;
this->values_[CountValueIndex] = 0;
this->mu_.unlock();
}
/**
* Merges two MinMaxSumCount aggregators together
*
* @param other the aggregator to merge with this aggregator
*/
void merge(const MinMaxSumCountAggregator &other)
{
if (this->kind_ == other.kind_)
{
this->mu_.lock();
// First merge values
// set min
if (this->values_[CountValueIndex] == 0 ||
other.values_[MinValueIndex] < this->values_[MinValueIndex])
this->values_[MinValueIndex] = other.values_[MinValueIndex];
// set max
if (this->values_[CountValueIndex] == 0 ||
other.values_[MaxValueIndex] > this->values_[MaxValueIndex])
this->values_[MaxValueIndex] = other.values_[MaxValueIndex];
// set sum
this->values_[SumValueIndex] += other.values_[SumValueIndex];
// set count
this->values_[CountValueIndex] += other.values_[CountValueIndex];
// Now merge checkpoints
if (this->checkpoint_[CountValueIndex] == 0 ||
other.checkpoint_[MinValueIndex] < this->checkpoint_[MinValueIndex])
this->checkpoint_[MinValueIndex] = other.checkpoint_[MinValueIndex];
// set max
if (this->checkpoint_[CountValueIndex] == 0 ||
other.checkpoint_[MaxValueIndex] > this->checkpoint_[MaxValueIndex])
this->checkpoint_[MaxValueIndex] = other.checkpoint_[MaxValueIndex];
// set sum
this->checkpoint_[SumValueIndex] += other.checkpoint_[SumValueIndex];
// set count
this->checkpoint_[CountValueIndex] += other.checkpoint_[CountValueIndex];
this->mu_.unlock();
}
else
{
// Log error
return;
}
}
/**
* Returns the checkpointed value
*
* @return the value of the checkpoint
*/
std::vector<T> get_checkpoint() override { return this->checkpoint_; }
/**
* Returns the values currently held by the aggregator
*
* @return the values held by the aggregator
*/
std::vector<T> get_values() override { return this->values_; }
};
} // namespace metrics
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,282 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef ENABLE_METRICS_PREVIEW
# include <algorithm>
# include <cmath>
# include <limits>
# include <map>
# include <mutex>
# include <stdexcept>
# include <vector>
# include "opentelemetry/_metrics/instrument.h"
# include "opentelemetry/sdk/_metrics/aggregator/aggregator.h"
# include "opentelemetry/version.h"
OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace metrics
{
/** Sketch Aggregators implement the DDSketch data type. Note that data is compressed
* by the DDSketch algorithm and users should be informed about its behavior before
* selecting it as the aggregation type. NOTE: The current implementation can only support
* non-negative values.
*
* Detailed information about the algorithm can be found in the following paper
* published by Datadog: http://www.vldb.org/pvldb/vol12/p2195-masson.pdf
*/
template <class T>
class SketchAggregator final : public Aggregator<T>
{
public:
/**
* Given the distribution of data this aggregator is designed for and its usage, the raw updates
*are stored in a map rather than a vector.
*
*@param kind, the instrument kind creating this aggregator
*@param error_bound, what is referred to as "alpha" in the DDSketch algorithm
*@param max_buckets, the maximum number of indices in the raw value map
*/
SketchAggregator(opentelemetry::metrics::InstrumentKind kind,
double error_bound,
size_t max_buckets = 2048)
{
this->kind_ = kind;
this->agg_kind_ = AggregatorKind::Sketch;
this->values_ = std::vector<T>(2, 0); // Sum in [0], Count in [1]
this->checkpoint_ = std::vector<T>(2, 0);
max_buckets_ = max_buckets;
error_bound_ = error_bound;
gamma = (1 + error_bound) / (1 - error_bound);
}
/**
* Update the aggregator with the new value. For a DDSketch aggregator, if the addition of this
* value creates a new bucket which is in excess of the maximum allowed size, the lowest indexes
* buckets are merged.
*
* @param val, the raw value used in aggregation
* @return none
*/
void update(T val) override
{
this->mu_.lock();
this->updated_ = true;
int idx;
if (val == 0)
{
idx = (std::numeric_limits<int>::min());
}
else
{
idx = static_cast<int>(ceil(log(val) / log(gamma)));
}
if (raw_.find(idx) != raw_.end())
{
raw_[idx] += 1;
}
else
{
raw_[idx] = 1;
}
this->values_[1] += 1;
this->values_[0] += val;
if (raw_.size() > max_buckets_)
{
int minidx = raw_.begin()->first, minidxval = raw_.begin()->second;
raw_.erase(minidx);
raw_[raw_.begin()->first] += minidxval;
}
this->mu_.unlock();
}
/**
* Calculate and return the value of a user specified quantile.
*
* @param q, the quantile to calculate (for example 0.5 is equivalent to the 50th percentile)
*/
virtual T get_quantiles(double q) override
{
if (q < 0 || q > 1)
{
# if __EXCEPTIONS
throw std::invalid_argument("Quantile values must fall between 0 and 1");
# else
std::terminate();
# endif
}
auto iter = checkpoint_raw_.begin();
int idx = iter->first;
int count = iter->second;
while (count < (q * (this->checkpoint_[1] - 1)) && iter != checkpoint_raw_.end())
{
iter++;
idx = iter->first;
count += iter->second;
}
return static_cast<T>(round(2 * pow(gamma, idx) / (gamma + 1)));
}
/**
* Checkpoints the current value. This function will overwrite the current checkpoint with the
* current value.
*
* @param none
* @return none
*/
void checkpoint() override
{
this->mu_.lock();
this->updated_ = false;
this->checkpoint_ = this->values_;
checkpoint_raw_ = raw_;
this->values_[0] = 0;
this->values_[1] = 0;
raw_.clear();
this->mu_.unlock();
}
/**
* Merges this sketch aggregator with another. The same bucket compression used when
* updating values is employed here to manage bucket size if the merging of aggregators
* results in more buckets than allowed.
*
* @param other, the aggregator with merge with
* @return none
*/
void merge(SketchAggregator other)
{
if (gamma != other.gamma)
{
# if __EXCEPTIONS
throw std::invalid_argument("Aggregators must have identical error tolerance");
# else
std::terminate();
# endif
}
else if (max_buckets_ != other.max_buckets_)
{
# if __EXCEPTIONS
throw std::invalid_argument("Aggregators must have the same maximum bucket allowance");
# else
std::terminate();
# endif
}
this->mu_.lock();
this->values_[0] += other.values_[0];
this->values_[1] += other.values_[1];
this->checkpoint_[0] += other.checkpoint_[0];
this->checkpoint_[1] += other.checkpoint_[1];
auto other_iter = other.raw_.begin();
while (other_iter != other.raw_.end())
{
raw_[other_iter->first] += other_iter->second;
if (raw_.size() > max_buckets_)
{
int minidx = raw_.begin()->first, minidxval = raw_.begin()->second;
raw_.erase(minidx);
raw_[raw_.begin()->first] += minidxval;
}
other_iter++;
}
auto other_ckpt_iter = other.checkpoint_raw_.begin();
while (other_ckpt_iter != other.checkpoint_raw_.end())
{
checkpoint_raw_[other_ckpt_iter->first] += other_ckpt_iter->second;
if (checkpoint_raw_.size() > max_buckets_)
{
int minidx = checkpoint_raw_.begin()->first, minidxval = checkpoint_raw_.begin()->second;
checkpoint_raw_.erase(minidx);
checkpoint_raw_[checkpoint_raw_.begin()->first] += minidxval;
}
other_ckpt_iter++;
}
this->mu_.unlock();
}
/**
* Returns the checkpointed value
*
* @param none
* @return the value of the checkpoint
*/
std::vector<T> get_checkpoint() override { return this->checkpoint_; }
/**
* Returns the current values
*
* @param none
* @return the present aggregator values
*/
std::vector<T> get_values() override { return this->values_; }
/**
* Returns the indices (or values) stored by this sketch aggregator.
*
* @param none
* @return a vector of all values the aggregator is currently tracking
*/
virtual std::vector<double> get_boundaries() override
{
std::vector<double> ret;
for (auto const &x : checkpoint_raw_)
{
ret.push_back(2 * pow(gamma, x.first) / (gamma + 1));
}
return ret;
}
/**
* Returns the error bound
*
* @param none
* @return the error bound specified during construction
*/
virtual double get_error_bound() override { return error_bound_; }
/**
* Returns the maximum allowed buckets
*
* @param none
* @return the maximum allowed buckets
*/
virtual size_t get_max_buckets() override { return max_buckets_; }
/**
* Returns the count of each value tracked by this sketch aggregator. These are returned
* in the same order as the indices returned by the get_boundaries function.
*
* @param none
* @return a vector of all counts for values tracked by the aggregator
*/
virtual std::vector<int> get_counts() override
{
std::vector<int> ret;
for (auto const &x : checkpoint_raw_)
{
ret.push_back(x.second);
}
return ret;
}
private:
double gamma;
double error_bound_;
size_t max_buckets_;
std::map<int, int> raw_;
std::map<int, int> checkpoint_raw_;
};
} // namespace metrics
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,286 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef ENABLE_METRICS_PREVIEW
# include <map>
# include <memory>
# include <sstream>
# include <stdexcept>
# include <vector>
# include "opentelemetry/_metrics/async_instruments.h"
# include "opentelemetry/sdk/_metrics/aggregator/counter_aggregator.h"
# include "opentelemetry/sdk/_metrics/aggregator/min_max_sum_count_aggregator.h"
# include "opentelemetry/sdk/_metrics/instrument.h"
# include "opentelemetry/version.h"
OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace metrics
{
# if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable : 4250) // inheriting methods via dominance
# endif
template <class T>
class ValueObserver : public AsynchronousInstrument<T>,
virtual public opentelemetry::metrics::ValueObserver<T>
{
public:
ValueObserver() = default;
ValueObserver(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
bool enabled,
void (*callback)(opentelemetry::metrics::ObserverResult<T>))
: AsynchronousInstrument<T>(name,
description,
unit,
enabled,
callback,
opentelemetry::metrics::InstrumentKind::ValueObserver)
{}
/*
* Updates the instruments aggregator with the new value. The labels should
* contain the keys and values to be associated with this value.
*
* @param value is the numerical representation of the metric being captured
* @param labels the set of labels, as key-value pairs
*/
virtual void observe(T value, const opentelemetry::common::KeyValueIterable &labels) override
{
this->mu_.lock();
std::string labelset = KvToString(labels);
if (boundAggregators_.find(labelset) == boundAggregators_.end())
{
auto sp1 = std::shared_ptr<Aggregator<T>>(new MinMaxSumCountAggregator<T>(this->kind_));
boundAggregators_.insert(std::make_pair(labelset, sp1));
sp1->update(value);
}
else
{
boundAggregators_[labelset]->update(value);
}
this->mu_.unlock();
}
/*
* Activate the instrument's callback function to record a measurement. This
* function will be called by the specified controller at a regular interval.
*
* @param none
* @return none
*/
virtual void run() override
{
opentelemetry::metrics::ObserverResult<T> res(this);
this->callback_(res);
}
virtual std::vector<Record> GetRecords() override
{
this->mu_.lock();
std::vector<Record> ret;
for (auto x : boundAggregators_)
{
x.second->checkpoint();
ret.push_back(Record(this->GetName(), this->GetDescription(), x.first, x.second));
}
boundAggregators_.clear();
this->mu_.unlock();
return ret;
}
// Public mapping from labels (stored as strings) to their respective aggregators
std::unordered_map<std::string, std::shared_ptr<Aggregator<T>>> boundAggregators_;
};
template <class T>
class SumObserver : public AsynchronousInstrument<T>,
virtual public opentelemetry::metrics::SumObserver<T>
{
public:
SumObserver() = default;
SumObserver(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
bool enabled,
void (*callback)(opentelemetry::metrics::ObserverResult<T>))
: AsynchronousInstrument<T>(name,
description,
unit,
enabled,
callback,
opentelemetry::metrics::InstrumentKind::SumObserver)
{}
/*
* Updates the instruments aggregator with the new value. The labels should
* contain the keys and values to be associated with this value.
*
* @param value is the numerical representation of the metric being captured
* @param labels the set of labels, as key-value pairs
*/
virtual void observe(T value, const opentelemetry::common::KeyValueIterable &labels) override
{
this->mu_.lock();
std::string labelset = KvToString(labels);
if (boundAggregators_.find(labelset) == boundAggregators_.end())
{
auto sp1 = std::shared_ptr<Aggregator<T>>(new CounterAggregator<T>(this->kind_));
boundAggregators_.insert(std::make_pair(labelset, sp1));
if (value < 0)
{
# if __EXCEPTIONS
throw std::invalid_argument("Counter instrument updates must be non-negative.");
# else
std::terminate();
# endif
}
else
{
sp1->update(value);
}
}
else
{
if (value < 0)
{
# if __EXCEPTIONS
throw std::invalid_argument("Counter instrument updates must be non-negative.");
# else
std::terminate();
# endif
}
else
{
boundAggregators_[labelset]->update(value);
}
}
this->mu_.unlock();
}
/*
* Activate the intsrument's callback function to record a measurement. This
* function will be called by the specified controller at a regular interval.
*
* @param none
* @return none
*/
virtual void run() override
{
opentelemetry::metrics::ObserverResult<T> res(this);
this->callback_(res);
}
virtual std::vector<Record> GetRecords() override
{
this->mu_.lock();
std::vector<Record> ret;
for (auto x : boundAggregators_)
{
x.second->checkpoint();
ret.push_back(Record(this->GetName(), this->GetDescription(), x.first, x.second));
}
boundAggregators_.clear();
this->mu_.unlock();
return ret;
}
// Public mapping from labels (stored as strings) to their respective aggregators
std::unordered_map<std::string, std::shared_ptr<Aggregator<T>>> boundAggregators_;
};
template <class T>
class UpDownSumObserver : public AsynchronousInstrument<T>,
virtual public opentelemetry::metrics::UpDownSumObserver<T>
{
public:
UpDownSumObserver() = default;
UpDownSumObserver(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
bool enabled,
void (*callback)(opentelemetry::metrics::ObserverResult<T>))
: AsynchronousInstrument<T>(name,
description,
unit,
enabled,
callback,
opentelemetry::metrics::InstrumentKind::UpDownSumObserver)
{}
/*
* Updates the instruments aggregator with the new value. The labels should
* contain the keys and values to be associated with this value.
*
* @param value is the numerical representation of the metric being captured
* @param labels the set of labels, as key-value pairs
*/
virtual void observe(T value, const opentelemetry::common::KeyValueIterable &labels) override
{
this->mu_.lock();
std::string labelset = KvToString(labels);
if (boundAggregators_.find(labelset) == boundAggregators_.end())
{
auto sp1 = std::shared_ptr<Aggregator<T>>(new CounterAggregator<T>(this->kind_));
boundAggregators_.insert(std::make_pair(labelset, sp1));
sp1->update(value);
}
else
{
boundAggregators_[labelset]->update(value);
}
this->mu_.unlock();
}
/*
* Activate the intsrument's callback function to record a measurement. This
* function will be called by the specified controller at a regular interval.
*
* @param none
* @return none
*/
virtual void run() override
{
opentelemetry::metrics::ObserverResult<T> res(this);
this->callback_(res);
}
virtual std::vector<Record> GetRecords() override
{
this->mu_.lock();
std::vector<Record> ret;
for (auto x : boundAggregators_)
{
x.second->checkpoint();
ret.push_back(Record(this->GetName(), this->GetDescription(), x.first, x.second));
}
boundAggregators_.clear();
this->mu_.unlock();
return ret;
}
// Public mapping from labels (stored as strings) to their respective aggregators
std::unordered_map<std::string, std::shared_ptr<Aggregator<T>>> boundAggregators_;
};
# if defined(_MSC_VER)
# pragma warning(pop)
# endif
} // namespace metrics
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,154 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef ENABLE_METRICS_PREVIEW
# include <atomic>
# include <iostream>
# include <sstream>
# include <thread>
# include <vector>
# include "opentelemetry/_metrics/instrument.h"
# include "opentelemetry/common/macros.h"
# include "opentelemetry/nostd/unique_ptr.h"
# include "opentelemetry/sdk/_metrics/exporter.h"
# include "opentelemetry/sdk/_metrics/meter.h"
# include "opentelemetry/sdk/_metrics/processor.h"
# include "opentelemetry/sdk/_metrics/record.h"
# include "opentelemetry/version.h"
OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace metrics
{
class PushController
{
public:
PushController(nostd::shared_ptr<opentelemetry::metrics::Meter> meter,
nostd::unique_ptr<MetricsExporter> exporter,
nostd::shared_ptr<MetricsProcessor> processor,
double period,
int timeout = 30)
{
meter_ = meter;
exporter_ = std::move(exporter);
processor_ = processor;
timeout_ = (unsigned int)(timeout * 1000000); // convert seconds to microseconds
period_ = (unsigned int)(period * 1000000);
}
/*
* Used to check if the metrics pipeline is currently active
*
* @param none
* @return true when active, false when on standby. This is a best guess estimate
* and the boolean from start() should be used to determine wheher the pipeline
* was initiated successfully.
*/
bool isActive() { return active_.load(); }
/*
* Begins the data processing and export pipeline. The function first ensures that the pipeline
* is not already running. If not, it begins and detaches a new thread for the Controller's run
* function which periodically polls the instruments for their data.
*
* @param none
* @return a boolean which is true when the pipeline is successfully started and false when
* already active
*/
bool start()
{
if (!active_.exchange(true))
{
runner_ = std::thread(&PushController::run, this);
return true;
}
return false;
}
/*
* Ends the processing and export pipeline then exports metrics one last time
* before returning.
*
* @param none
* @return none
*/
void stop()
{
if (active_.exchange(false))
{
if (runner_.joinable())
{
runner_.join();
}
tick(); // flush metrics sitting in the processor
}
}
private:
/*
* Run the tick function at a regular interval. This function
* should be run in its own thread.
*
* Used to wait between collection intervals.
*/
void run()
{
if (!running_.exchange(true))
{
while (active_.load())
{
tick();
std::this_thread::sleep_for(std::chrono::microseconds(period_));
}
running_.exchange(false);
}
}
/*
* Tick
*
* Called at regular intervals, this function collects all values from the
* member variable meter_, then sends them to the processor_ for
* processing. After the records have been processed they are sent to the
* exporter_ to be exported.
*
*/
void tick()
{
this->mu_.lock();
# ifdef OPENTELEMETRY_RTTI_ENABLED
std::vector<Record> collected = dynamic_cast<Meter *>(meter_.get())->Collect();
# else
std::vector<Record> collected = static_cast<Meter *>(meter_.get())->Collect();
# endif
for (const auto &rec : collected)
{
processor_->process(rec);
}
collected = processor_->CheckpointSelf();
processor_->FinishedCollection();
exporter_->Export(collected);
this->mu_.unlock();
}
nostd::shared_ptr<opentelemetry::metrics::Meter> meter_;
nostd::unique_ptr<MetricsExporter> exporter_;
nostd::shared_ptr<MetricsProcessor> processor_;
std::thread runner_;
std::mutex mu_;
std::atomic<bool> active_ = ATOMIC_VAR_INIT(false);
std::atomic<bool> running_ = ATOMIC_VAR_INIT(false);
unsigned int period_;
unsigned int timeout_;
};
} // namespace metrics
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,35 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef ENABLE_METRICS_PREVIEW
# include <memory>
# include "opentelemetry/sdk/_metrics/record.h"
# include "opentelemetry/sdk/common/exporter_utils.h"
OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace metrics
{
/**
* MetricsExporter defines the interface that protocol-specific span exporters must
* implement.
*/
class MetricsExporter
{
public:
virtual ~MetricsExporter() = default;
/**
* Exports a vector of Records. This method must not be called
* concurrently for the same exporter instance.
* @param records a vector of unique pointers to metric records
*/
virtual sdk::common::ExportResult Export(const std::vector<Record> &records) noexcept = 0;
};
} // namespace metrics
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,312 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef ENABLE_METRICS_PREVIEW
# include <iostream>
# include <map>
# include <memory>
# include <sstream>
# include <string>
# include <unordered_map>
# include <vector>
# include "opentelemetry/_metrics/instrument.h"
# include "opentelemetry/sdk/_metrics/aggregator/aggregator.h"
# include "opentelemetry/sdk/_metrics/record.h"
# include "opentelemetry/version.h"
OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace metrics
{
# if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable : 4250) // inheriting methods via dominance
# endif
class Instrument : virtual public opentelemetry::metrics::Instrument
{
public:
Instrument() = default;
Instrument(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
bool enabled,
opentelemetry::metrics::InstrumentKind kind)
: name_(name), description_(description), unit_(unit), enabled_(enabled), kind_(kind)
{}
// Returns true if the instrument is enabled and collecting data
virtual bool IsEnabled() override { return enabled_; }
// Return the instrument name
virtual nostd::string_view GetName() override { return name_; }
// Return the instrument description
virtual nostd::string_view GetDescription() override { return description_; }
// Return the insrument's units of measurement
virtual nostd::string_view GetUnits() override { return unit_; }
virtual opentelemetry::metrics::InstrumentKind GetKind() override { return this->kind_; }
protected:
std::string name_;
std::string description_;
std::string unit_;
bool enabled_;
std::mutex mu_;
opentelemetry::metrics::InstrumentKind kind_;
};
template <class T>
class BoundSynchronousInstrument
: public Instrument,
virtual public opentelemetry::metrics::BoundSynchronousInstrument<T>
{
public:
BoundSynchronousInstrument() = default;
BoundSynchronousInstrument(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
bool enabled,
opentelemetry::metrics::InstrumentKind kind,
std::shared_ptr<Aggregator<T>> agg)
: Instrument(name, description, unit, enabled, kind), agg_(agg)
{
this->inc_ref(); // increase reference count when instantiated
}
/**
* Frees the resources associated with this Bound Instrument.
* The Metric from which this instrument was created is not impacted.
*
* @param none
* @return void
*/
virtual void unbind() override
{
this->mu_.lock();
ref_ -= 1;
this->mu_.unlock();
}
/**
* Increments the reference count. This function is used when binding or instantiating.
*
* @param none
* @return void
*/
virtual void inc_ref() override
{
this->mu_.lock();
ref_ += 1;
this->mu_.unlock();
}
/**
* Returns the current reference count of the instrument. This value is used to
* later in the pipeline remove stale instruments.
*
* @param none
* @return current ref count of the instrument
*/
virtual int get_ref() override
{
this->mu_.lock();
auto ret = ref_;
this->mu_.unlock();
return ret;
}
/**
* Records a single synchronous metric event via a call to the aggregator.
* Since this is a bound synchronous instrument, labels are not required in
* metric capture calls.
*
* @param value is the numerical representation of the metric being captured
* @return void
*/
virtual void update(T value) override
{
this->mu_.lock();
agg_->update(value);
this->mu_.unlock();
}
/**
* Returns the aggregator responsible for meaningfully combining update values.
*
* @param none
* @return the aggregator assigned to this instrument
*/
virtual std::shared_ptr<Aggregator<T>> GetAggregator() final { return agg_; }
private:
std::shared_ptr<Aggregator<T>> agg_;
int ref_ = 0;
};
template <class T>
class SynchronousInstrument : public Instrument,
virtual public opentelemetry::metrics::SynchronousInstrument<T>
{
public:
SynchronousInstrument() = default;
SynchronousInstrument(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
bool enabled,
opentelemetry::metrics::InstrumentKind kind)
: Instrument(name, description, unit, enabled, kind)
{}
/**
* Returns a Bound Instrument associated with the specified labels. Multiples requests
* with the same set of labels may return the same Bound Instrument instance.
*
* It is recommended that callers keep a reference to the Bound Instrument
* instead of repeatedly calling this operation.
*
* @param labels the set of labels, as key-value pairs
* @return a Bound Instrument
*/
virtual nostd::shared_ptr<opentelemetry::metrics::BoundSynchronousInstrument<T>> bind(
const opentelemetry::common::KeyValueIterable &labels) override
{
return nostd::shared_ptr<BoundSynchronousInstrument<T>>();
}
// This function is necessary for batch recording and should NOT be called by the user
virtual void update(T value, const opentelemetry::common::KeyValueIterable &labels) override = 0;
/**
* Checkpoints instruments and returns a set of records which are ready for processing.
* This method should ONLY be called by the Meter Class as part of the export pipeline
* as it also prunes bound instruments with no active references.
*
* @param none
* @return vector of Records which hold the data attached to this synchronous instrument
*/
virtual std::vector<Record> GetRecords() = 0;
};
template <class T>
class AsynchronousInstrument : public Instrument,
virtual public opentelemetry::metrics::AsynchronousInstrument<T>
{
public:
AsynchronousInstrument() = default;
AsynchronousInstrument(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
bool enabled,
void (*callback)(opentelemetry::metrics::ObserverResult<T>),
opentelemetry::metrics::InstrumentKind kind)
: Instrument(name, description, unit, enabled, kind)
{
this->callback_ = callback;
}
/**
* Captures data through a manual call rather than the automatic collection process instituted
* in the run function. Asynchronous instruments are generally expected to obtain data from
* their callbacks rather than direct calls. This function is used by the callback to store data.
*
* @param value is the numerical representation of the metric being captured
* @param labels is the numerical representation of the metric being captured
* @return none
*/
virtual void observe(T value, const opentelemetry::common::KeyValueIterable &labels) override = 0;
virtual std::vector<Record> GetRecords() = 0;
/**
* Captures data by activating the callback function associated with the
* instrument and storing its return value. Callbacks for asynchronous
* instruments are defined during construction.
*
* @param none
* @return none
*/
virtual void run() override = 0;
};
// Helper functions for turning a common::KeyValueIterable into a string
inline void print_value(std::stringstream &ss,
opentelemetry::common::AttributeValue &value,
bool jsonTypes = false)
{
switch (value.index())
{
case opentelemetry::common::AttributeType::kTypeString:
ss << nostd::get<nostd::string_view>(value);
break;
default:
# if __EXCEPTIONS
throw std::invalid_argument("Labels must be strings");
# else
std::terminate();
# endif
break;
}
};
// Utility function which converts maps to strings for better performance
inline std::string mapToString(const std::map<std::string, std::string> &conv)
{
std::stringstream ss;
ss << "{";
for (auto i : conv)
{
ss << i.first << ':' << i.second << ',';
}
ss << "}";
return ss.str();
}
inline std::string KvToString(const opentelemetry::common::KeyValueIterable &kv) noexcept
{
std::stringstream ss;
ss << "{";
size_t size = kv.size();
if (size)
{
size_t i = 1;
kv.ForEachKeyValue(
[&](nostd::string_view key, opentelemetry::common::AttributeValue value) noexcept {
ss << key << ":";
print_value(ss, value, true);
if (size != i)
{
ss << ",";
}
i++;
return true;
});
};
ss << "}";
return ss.str();
}
# if defined(_MSC_VER)
# pragma warning(pop)
# endif
} // namespace metrics
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,392 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef ENABLE_METRICS_PREVIEW
# include "opentelemetry/_metrics/meter.h"
# include "opentelemetry/nostd/shared_ptr.h"
# include "opentelemetry/sdk/_metrics/async_instruments.h"
# include "opentelemetry/sdk/_metrics/instrument.h"
# include "opentelemetry/sdk/_metrics/record.h"
# include "opentelemetry/sdk/_metrics/sync_instruments.h"
# include <unordered_set>
# include <vector>
OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace metrics
{
class Meter : public opentelemetry::metrics::Meter
{
public:
explicit Meter(std::string library_name, std::string library_version = "")
{
library_name_ = library_name;
library_version_ = library_version;
}
/**
* Creates a Counter with the passed characteristics and returns a shared_ptr to that Counter.
*
* @param name the name of the new Counter.
* @param description a brief description of what the Counter is used for.
* @param unit the unit of metric values following https://unitsofmeasure.org/ucum.html.
* @param enabled a boolean value that turns on or off the metric instrument.
* @return a shared pointer to the created Counter.
* @throws invalid_argument exception if name is null or does not conform to OTel syntax.
*/
nostd::shared_ptr<opentelemetry::metrics::Counter<short>> NewShortCounter(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) override;
nostd::shared_ptr<opentelemetry::metrics::Counter<int>> NewIntCounter(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) override;
nostd::shared_ptr<opentelemetry::metrics::Counter<float>> NewFloatCounter(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) override;
nostd::shared_ptr<opentelemetry::metrics::Counter<double>> NewDoubleCounter(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) override;
/**
* Creates an UpDownCounter with the passed characteristics and returns a shared_ptr to that
* UpDownCounter.
*
* @param name the name of the new UpDownCounter.
* @param description a brief description of what the UpDownCounter is used for.
* @param unit the unit of metric values following https://unitsofmeasure.org/ucum.html.
* @param enabled a boolean value that turns on or off the metric instrument.
* @return a shared pointer to the created UpDownCounter.
* @throws invalid_argument exception if name is null or does not conform to OTel syntax.
*/
nostd::shared_ptr<opentelemetry::metrics::UpDownCounter<short>> NewShortUpDownCounter(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) override;
nostd::shared_ptr<opentelemetry::metrics::UpDownCounter<int>> NewIntUpDownCounter(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) override;
nostd::shared_ptr<opentelemetry::metrics::UpDownCounter<float>> NewFloatUpDownCounter(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) override;
nostd::shared_ptr<opentelemetry::metrics::UpDownCounter<double>> NewDoubleUpDownCounter(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) override;
/**
* Creates a ValueRecorder with the passed characteristics and returns a shared_ptr to that
* ValueRecorder.
*
* @param name the name of the new ValueRecorder.
* @param description a brief description of what the ValueRecorder is used for.
* @param unit the unit of metric values following https://unitsofmeasure.org/ucum.html.
* @param enabled a boolean value that turns on or off the metric instrument.
* @return a shared pointer to the created DoubleValueRecorder.
* @throws invalid_argument exception if name is null or does not conform to OTel syntax.
*/
nostd::shared_ptr<opentelemetry::metrics::ValueRecorder<short>> NewShortValueRecorder(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) override;
nostd::shared_ptr<opentelemetry::metrics::ValueRecorder<int>> NewIntValueRecorder(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) override;
nostd::shared_ptr<opentelemetry::metrics::ValueRecorder<float>> NewFloatValueRecorder(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) override;
nostd::shared_ptr<opentelemetry::metrics::ValueRecorder<double>> NewDoubleValueRecorder(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled) override;
/**
* Creates a SumObserver with the passed characteristics and returns a shared_ptr to that
* SumObserver.
*
* @param name the name of the new SumObserver.
* @param description a brief description of what the SumObserver is used for.
* @param unit the unit of metric values following https://unitsofmeasure.org/ucum.html.
* @param enabled a boolean value that turns on or off the metric instrument.
* @param callback the function to be observed by the instrument.
* @return a shared pointer to the created SumObserver.
* @throws invalid_argument exception if name is null or does not conform to OTel syntax.
*/
nostd::shared_ptr<opentelemetry::metrics::SumObserver<short>> NewShortSumObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(opentelemetry::metrics::ObserverResult<short>)) override;
nostd::shared_ptr<opentelemetry::metrics::SumObserver<int>> NewIntSumObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(opentelemetry::metrics::ObserverResult<int>)) override;
nostd::shared_ptr<opentelemetry::metrics::SumObserver<float>> NewFloatSumObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(opentelemetry::metrics::ObserverResult<float>)) override;
nostd::shared_ptr<opentelemetry::metrics::SumObserver<double>> NewDoubleSumObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(opentelemetry::metrics::ObserverResult<double>)) override;
/**
* Creates an UpDownSumObserver with the passed characteristics and returns a shared_ptr to
* that UpDowNSumObserver.
*
* @param name the name of the new UpDownSumObserver.
* @param description a brief description of what the UpDownSumObserver is used for.
* @param unit the unit of metric values following https://unitsofmeasure.org/ucum.html.
* @param enabled a boolean value that turns on or off the metric instrument.
* @param callback the function to be observed by the instrument.
* @return a shared pointer to the created UpDownSumObserver.
* @throws invalid_argument exception if name is null or does not conform to OTel syntax.
*/
nostd::shared_ptr<opentelemetry::metrics::UpDownSumObserver<short>> NewShortUpDownSumObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(opentelemetry::metrics::ObserverResult<short>)) override;
nostd::shared_ptr<opentelemetry::metrics::UpDownSumObserver<int>> NewIntUpDownSumObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(opentelemetry::metrics::ObserverResult<int>)) override;
nostd::shared_ptr<opentelemetry::metrics::UpDownSumObserver<float>> NewFloatUpDownSumObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(opentelemetry::metrics::ObserverResult<float>)) override;
nostd::shared_ptr<opentelemetry::metrics::UpDownSumObserver<double>> NewDoubleUpDownSumObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(opentelemetry::metrics::ObserverResult<double>)) override;
/**
* Creates a ValueObserver with the passed characteristics and returns a shared_ptr to that
* ValueObserver.
*
* @param name the name of the new ValueObserver.
* @param description a brief description of what the ValueObserver is used for.
* @param unit the unit of metric values following https://unitsofmeasure.org/ucum.html.
* @param enabled a boolean value that turns on or off the metric instrument.
* @param callback the function to be observed by the instrument.
* @return a shared pointer to the created ValueObserver.
* @throws invalid_argument exception if name is null or does not conform to OTel syntax.
*/
nostd::shared_ptr<opentelemetry::metrics::ValueObserver<short>> NewShortValueObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(opentelemetry::metrics::ObserverResult<short>)) override;
nostd::shared_ptr<opentelemetry::metrics::ValueObserver<int>> NewIntValueObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(opentelemetry::metrics::ObserverResult<int>)) override;
nostd::shared_ptr<opentelemetry::metrics::ValueObserver<float>> NewFloatValueObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(opentelemetry::metrics::ObserverResult<float>)) override;
nostd::shared_ptr<opentelemetry::metrics::ValueObserver<double>> NewDoubleValueObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(opentelemetry::metrics::ObserverResult<double>)) override;
/**
* Utility method that allows users to atomically record measurements to a set of
* synchronous metric instruments with a common set of labels.
*
* @param labels the set of labels to associate with this recorder.
* @param values a span of pairs where the first element of the pair is a metric instrument
* to record to, and the second element is the value to update that instrument with.
*/
void RecordShortBatch(
const opentelemetry::common::KeyValueIterable &labels,
nostd::span<opentelemetry::metrics::SynchronousInstrument<short> *> instruments,
nostd::span<const short> values) noexcept override;
void RecordIntBatch(const opentelemetry::common::KeyValueIterable &labels,
nostd::span<opentelemetry::metrics::SynchronousInstrument<int> *> instruments,
nostd::span<const int> values) noexcept override;
void RecordFloatBatch(
const opentelemetry::common::KeyValueIterable &labels,
nostd::span<opentelemetry::metrics::SynchronousInstrument<float> *> instruments,
nostd::span<const float> values) noexcept override;
void RecordDoubleBatch(
const opentelemetry::common::KeyValueIterable &labels,
nostd::span<opentelemetry::metrics::SynchronousInstrument<double> *> instruments,
nostd::span<const double> values) noexcept override;
/**
* An SDK-only function that checkpoints the aggregators of all instruments created from
* this meter, creates a {@code Record} out of them, and sends them for export.
*
* @return A vector of {@code Records} to be sent to the processor.
*/
std::vector<Record> Collect() noexcept;
private:
/**
* A private function that creates records from all synchronous instruments created from
* this meter.
*
* @param records A reference to the vector to push the new records to.
*/
void CollectMetrics(std::vector<Record> &records);
/**
* Helper function to collect Records from a single synchronous instrument
*
* @tparam T The integral type of the instrument to collect from.
* @param i A map iterator pointing to the instrument to collect from
* @param records The vector to add the new records to.
*/
template <typename T>
void CollectSingleSyncInstrument(
typename std::map<std::string,
std::shared_ptr<opentelemetry::metrics::SynchronousInstrument<T>>>::iterator
i,
std::vector<Record> &records);
/**
* A private function that creates records from all asynchronous instruments created from
* this meter.
*
* @param records A reference to the vector to push the new records to.
*/
void CollectObservers(std::vector<Record> &records);
/**
* Helper function to collect Records from a single asynchronous instrument
*
* @tparam T The integral type of the instrument to collect from.
* @param i A map iterator pointing to the instrument to collect from
* @param records The vector to add the new records to.
*/
template <typename T>
void CollectSingleAsyncInstrument(
typename std::map<
std::string,
std::shared_ptr<opentelemetry::metrics::AsynchronousInstrument<T>>>::iterator i,
std::vector<Record> &records);
/**
* Utility function used by the meter that checks if a user-passed name abides by OpenTelemetry
* naming rules. The rules are as follows:
* 1. The name must not be empty.
* 2. The name must not start with a digit, a space, or any punctuation.
* 3. The name must only have the following chaacters:
* All alphanumeric characters, '.', '_' and '-'.
*
* @param name The name to be examined for legality.
* @return A bool representing whether the name is valid by the OpenTelemetry syntax rules.
*/
bool IsValidName(nostd::string_view name);
/**
* A utility function used by the meter to determine whether an instrument of a specified
* name already exists in this meter.
*
* @param name The name to examine.
* @return A boolean representing whether the name has already been used by this meter.
*/
bool NameAlreadyUsed(nostd::string_view name);
/*
* All instruments must be stored in a map so the meter can collect on these instruments.
* Additionally, when creating a new instrument, the meter must check if an instrument of the same
* name already exists.
*/
std::map<std::string, std::shared_ptr<opentelemetry::metrics::SynchronousInstrument<short>>>
short_metrics_;
std::map<std::string, std::shared_ptr<opentelemetry::metrics::SynchronousInstrument<int>>>
int_metrics_;
std::map<std::string, std::shared_ptr<opentelemetry::metrics::SynchronousInstrument<float>>>
float_metrics_;
std::map<std::string, std::shared_ptr<opentelemetry::metrics::SynchronousInstrument<double>>>
double_metrics_;
std::map<std::string, std::shared_ptr<opentelemetry::metrics::AsynchronousInstrument<short>>>
short_observers_;
std::map<std::string, std::shared_ptr<opentelemetry::metrics::AsynchronousInstrument<int>>>
int_observers_;
std::map<std::string, std::shared_ptr<opentelemetry::metrics::AsynchronousInstrument<float>>>
float_observers_;
std::map<std::string, std::shared_ptr<opentelemetry::metrics::AsynchronousInstrument<double>>>
double_observers_;
std::unordered_set<std::string> names_;
std::string library_name_;
std::string library_version_;
std::mutex metrics_lock_;
std::mutex observers_lock_;
};
} // namespace metrics
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,37 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef ENABLE_METRICS_PREVIEW
# include "opentelemetry/_metrics/meter_provider.h"
# include "opentelemetry/nostd/shared_ptr.h"
# include "opentelemetry/sdk/_metrics/meter.h"
# include <memory>
# include <string>
OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace metrics
{
class MeterProvider final : public opentelemetry::metrics::MeterProvider
{
public:
/**
* Initialize a new meter provider
*/
explicit MeterProvider(std::string library_name = "", std::string library_version = "") noexcept;
opentelemetry::nostd::shared_ptr<opentelemetry::metrics::Meter> GetMeter(
nostd::string_view library_name,
nostd::string_view library_version = "") noexcept override;
private:
std::shared_ptr<opentelemetry::metrics::Meter> meter_;
};
} // namespace metrics
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,38 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef ENABLE_METRICS_PREVIEW
# include "opentelemetry/_metrics/instrument.h"
# include "opentelemetry/nostd/string_view.h"
# include "opentelemetry/sdk/_metrics/record.h"
# include "opentelemetry/version.h"
# include <iostream>
# include <string>
# include <unordered_map>
OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace metrics
{
class MetricsProcessor
{
public:
virtual ~MetricsProcessor() = default;
virtual std::vector<opentelemetry::sdk::metrics::Record> CheckpointSelf() noexcept = 0;
virtual void FinishedCollection() noexcept = 0;
virtual void process(opentelemetry::sdk::metrics::Record record) noexcept = 0;
};
} // namespace metrics
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,50 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef ENABLE_METRICS_PREVIEW
# include <memory>
# include "opentelemetry/_metrics/instrument.h"
# include "opentelemetry/nostd/variant.h"
# include "opentelemetry/sdk/_metrics/aggregator/aggregator.h"
OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace metrics
{
using AggregatorVariant = nostd::variant<std::shared_ptr<Aggregator<short>>,
std::shared_ptr<Aggregator<int>>,
std::shared_ptr<Aggregator<float>>,
std::shared_ptr<Aggregator<double>>>;
class Record
{
public:
explicit Record(nostd::string_view name,
nostd::string_view description,
std::string labels,
AggregatorVariant aggregator)
{
name_ = std::string(name);
description_ = std::string(description);
labels_ = labels;
aggregator_ = aggregator;
}
std::string GetName() { return name_; }
std::string GetDescription() { return description_; }
std::string GetLabels() { return labels_; }
AggregatorVariant GetAggregator() { return aggregator_; }
private:
std::string name_;
std::string description_;
std::string labels_;
AggregatorVariant aggregator_;
};
} // namespace metrics
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,465 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef ENABLE_METRICS_PREVIEW
# include <map>
# include <memory>
# include <sstream>
# include <stdexcept>
# include <vector>
# include "opentelemetry/_metrics/sync_instruments.h"
# include "opentelemetry/common/macros.h"
# include "opentelemetry/sdk/_metrics/aggregator/counter_aggregator.h"
# include "opentelemetry/sdk/_metrics/aggregator/min_max_sum_count_aggregator.h"
# include "opentelemetry/sdk/_metrics/instrument.h"
OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace metrics
{
# if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable : 4250) // inheriting methods via dominance
# endif
template <class T>
class BoundCounter final : public BoundSynchronousInstrument<T>,
public opentelemetry::metrics::BoundCounter<T>
{
public:
BoundCounter() = default;
BoundCounter(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
bool enabled)
: BoundSynchronousInstrument<T>(
name,
description,
unit,
enabled,
opentelemetry::metrics::InstrumentKind::Counter,
std::shared_ptr<Aggregator<T>>(new CounterAggregator<T>(
opentelemetry::metrics::InstrumentKind::Counter))) // Aggregator is chosen here
{}
/*
* Add adds the value to the counter's sum. The labels are already linked to the instrument
* and are not specified.
*
* @param value the numerical representation of the metric being captured
* @param labels the set of labels, as key-value pairs
*/
virtual void add(T value) override
{
if (value < 0)
{
# if __EXCEPTIONS
throw std::invalid_argument("Counter instrument updates must be non-negative.");
# else
std::terminate();
# endif
}
else
{
this->update(value);
}
}
};
template <class T>
class Counter final : public SynchronousInstrument<T>, public opentelemetry::metrics::Counter<T>
{
public:
Counter() = default;
Counter(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
bool enabled)
: SynchronousInstrument<T>(name,
description,
unit,
enabled,
opentelemetry::metrics::InstrumentKind::Counter)
{}
/*
* Bind creates a bound instrument for this counter. The labels are
* associated with values recorded via subsequent calls to Record.
*
* @param labels the set of labels, as key-value pairs.
* @return a BoundCounter tied to the specified labels
*/
virtual nostd::shared_ptr<opentelemetry::metrics::BoundCounter<T>> bindCounter(
const opentelemetry::common::KeyValueIterable &labels) override
{
this->mu_.lock();
std::string labelset = KvToString(labels);
if (boundInstruments_.find(labelset) == boundInstruments_.end())
{
auto sp1 = nostd::shared_ptr<opentelemetry::metrics::BoundCounter<T>>(
new BoundCounter<T>(this->name_, this->description_, this->unit_, this->enabled_));
boundInstruments_[labelset] = sp1;
this->mu_.unlock();
return sp1;
}
else
{
boundInstruments_[labelset]->inc_ref();
auto ret = boundInstruments_[labelset];
this->mu_.unlock();
return ret;
}
}
/*
* Add adds the value to the counter's sum. The labels should contain
* the keys and values to be associated with this value. Counters only
* accept positive valued updates.
*
* @param value the numerical representation of the metric being captured
* @param labels the set of labels, as key-value pairs
*/
virtual void add(T value, const opentelemetry::common::KeyValueIterable &labels) override
{
if (value < 0)
{
# if __EXCEPTIONS
throw std::invalid_argument("Counter instrument updates must be non-negative.");
# else
std::terminate();
# endif
}
else
{
auto sp = bindCounter(labels);
sp->update(value);
sp->unbind();
}
}
virtual std::vector<Record> GetRecords() override
{
this->mu_.lock();
std::vector<Record> ret;
std::vector<std::string> toDelete;
for (const auto &x : boundInstruments_)
{
if (x.second->get_ref() == 0)
{
toDelete.push_back(x.first);
}
# ifdef OPENTELEMETRY_RTTI_ENABLED
auto agg_ptr = dynamic_cast<BoundCounter<T> *>(x.second.get())->GetAggregator();
# else
auto agg_ptr = static_cast<BoundCounter<T> *>(x.second.get())->GetAggregator();
# endif
if (agg_ptr->is_updated())
{
agg_ptr->checkpoint();
ret.push_back(Record(x.second->GetName(), x.second->GetDescription(), x.first, agg_ptr));
}
}
for (const auto &x : toDelete)
{
boundInstruments_.erase(x);
}
this->mu_.unlock();
return ret;
}
virtual void update(T val, const opentelemetry::common::KeyValueIterable &labels) override
{
add(val, labels);
}
// A collection of the bound instruments created by this unbound instrument identified by their
// labels.
std::unordered_map<std::string, nostd::shared_ptr<opentelemetry::metrics::BoundCounter<T>>>
boundInstruments_;
};
template <class T>
class BoundUpDownCounter final : public BoundSynchronousInstrument<T>,
virtual public opentelemetry::metrics::BoundUpDownCounter<T>
{
public:
BoundUpDownCounter() = default;
BoundUpDownCounter(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
bool enabled)
: BoundSynchronousInstrument<T>(name,
description,
unit,
enabled,
opentelemetry::metrics::InstrumentKind::UpDownCounter,
std::shared_ptr<Aggregator<T>>(new CounterAggregator<T>(
opentelemetry::metrics::InstrumentKind::UpDownCounter)))
{}
/*
* Add adds the value to the counter's sum. The labels are already linked to the instrument
* and are not specified.
*
* @param value the numerical representation of the metric being captured
* @param labels the set of labels, as key-value pairs
*/
virtual void add(T value) override { this->update(value); }
};
template <class T>
class UpDownCounter final : public SynchronousInstrument<T>,
public opentelemetry::metrics::UpDownCounter<T>
{
public:
UpDownCounter() = default;
UpDownCounter(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
bool enabled)
: SynchronousInstrument<T>(name,
description,
unit,
enabled,
opentelemetry::metrics::InstrumentKind::UpDownCounter)
{}
/*
* Bind creates a bound instrument for this counter. The labels are
* associated with values recorded via subsequent calls to Record.
*
* @param labels the set of labels, as key-value pairs.
* @return a BoundIntCounter tied to the specified labels
*/
nostd::shared_ptr<opentelemetry::metrics::BoundUpDownCounter<T>> bindUpDownCounter(
const opentelemetry::common::KeyValueIterable &labels) override
{
this->mu_.lock();
std::string labelset = KvToString(labels);
if (boundInstruments_.find(labelset) == boundInstruments_.end())
{
auto sp1 = nostd::shared_ptr<opentelemetry::metrics::BoundUpDownCounter<T>>(
new BoundUpDownCounter<T>(this->name_, this->description_, this->unit_, this->enabled_));
boundInstruments_[labelset] = sp1;
this->mu_.unlock();
return sp1;
}
else
{
boundInstruments_[labelset]->inc_ref();
auto ret = boundInstruments_[labelset];
this->mu_.unlock();
return ret;
}
}
/*
* Add adds the value to the counter's sum. The labels should contain
* the keys and values to be associated with this value. Counters only
* accept positive valued updates.
*
* @param value the numerical representation of the metric being captured
* @param labels the set of labels, as key-value pairs
*/
void add(T value, const opentelemetry::common::KeyValueIterable &labels) override
{
auto sp = bindUpDownCounter(labels);
sp->update(value);
sp->unbind();
}
virtual std::vector<Record> GetRecords() override
{
this->mu_.lock();
std::vector<Record> ret;
std::vector<std::string> toDelete;
for (const auto &x : boundInstruments_)
{
if (x.second->get_ref() == 0)
{
toDelete.push_back(x.first);
}
# ifdef OPENTELEMETRY_RTTI_ENABLED
auto agg_ptr = dynamic_cast<BoundUpDownCounter<T> *>(x.second.get())->GetAggregator();
# else
auto agg_ptr = static_cast<BoundUpDownCounter<T> *>(x.second.get())->GetAggregator();
# endif
if (agg_ptr->is_updated())
{
agg_ptr->checkpoint();
ret.push_back(Record(x.second->GetName(), x.second->GetDescription(), x.first, agg_ptr));
}
}
for (const auto &x : toDelete)
{
boundInstruments_.erase(x);
}
this->mu_.unlock();
return ret;
}
virtual void update(T val, const opentelemetry::common::KeyValueIterable &labels) override
{
add(val, labels);
}
std::unordered_map<std::string, nostd::shared_ptr<opentelemetry::metrics::BoundUpDownCounter<T>>>
boundInstruments_;
};
template <class T>
class BoundValueRecorder final : public BoundSynchronousInstrument<T>,
public opentelemetry::metrics::BoundValueRecorder<T>
{
public:
BoundValueRecorder() = default;
BoundValueRecorder(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
bool enabled)
: BoundSynchronousInstrument<T>(
name,
description,
unit,
enabled,
opentelemetry::metrics::InstrumentKind::ValueRecorder,
std::shared_ptr<Aggregator<T>>(new MinMaxSumCountAggregator<T>(
opentelemetry::metrics::InstrumentKind::ValueRecorder)))
{}
/*
* Add adds the value to the counter's sum. The labels are already linked to the instrument
* and are not specified.
*
* @param value the numerical representation of the metric being captured
* @param labels the set of labels, as key-value pairs
*/
void record(T value) { this->update(value); }
};
template <class T>
class ValueRecorder final : public SynchronousInstrument<T>,
public opentelemetry::metrics::ValueRecorder<T>
{
public:
ValueRecorder() = default;
ValueRecorder(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
bool enabled)
: SynchronousInstrument<T>(name,
description,
unit,
enabled,
opentelemetry::metrics::InstrumentKind::ValueRecorder)
{}
/*
* Bind creates a bound instrument for this counter. The labels are
* associated with values recorded via subsequent calls to Record.
*
* @param labels the set of labels, as key-value pairs.
* @return a BoundIntCounter tied to the specified labels
*/
nostd::shared_ptr<opentelemetry::metrics::BoundValueRecorder<T>> bindValueRecorder(
const opentelemetry::common::KeyValueIterable &labels) override
{
this->mu_.lock();
std::string labelset = KvToString(labels);
if (boundInstruments_.find(labelset) == boundInstruments_.end())
{
auto sp1 = nostd::shared_ptr<opentelemetry::metrics::BoundValueRecorder<T>>(
new BoundValueRecorder<T>(this->name_, this->description_, this->unit_, this->enabled_));
boundInstruments_[labelset] = sp1;
this->mu_.unlock();
return sp1;
}
else
{
boundInstruments_[labelset]->inc_ref();
auto ret = boundInstruments_[labelset];
this->mu_.unlock();
return ret;
}
}
/*
* Add adds the value to the counter's sum. The labels should contain
* the keys and values to be associated with this value. Counters only
* accept positive valued updates.
*
* @param value the numerical representation of the metric being captured
* @param labels the set of labels, as key-value pairs
*/
void record(T value, const opentelemetry::common::KeyValueIterable &labels) override
{
auto sp = bindValueRecorder(labels);
sp->update(value);
sp->unbind();
}
virtual std::vector<Record> GetRecords() override
{
this->mu_.lock();
std::vector<Record> ret;
std::vector<std::string> toDelete;
for (const auto &x : boundInstruments_)
{
if (x.second->get_ref() == 0)
{
toDelete.push_back(x.first);
}
# ifdef OPENTELEMETRY_RTTI_ENABLED
auto agg_ptr = dynamic_cast<BoundValueRecorder<T> *>(x.second.get())->GetAggregator();
# else
auto agg_ptr = static_cast<BoundValueRecorder<T> *>(x.second.get())->GetAggregator();
# endif
if (agg_ptr->is_updated())
{
agg_ptr->checkpoint();
ret.push_back(Record(x.second->GetName(), x.second->GetDescription(), x.first, agg_ptr));
}
}
for (const auto &x : toDelete)
{
boundInstruments_.erase(x);
}
this->mu_.unlock();
return ret;
}
virtual void update(T value, const opentelemetry::common::KeyValueIterable &labels) override
{
record(value, labels);
}
std::unordered_map<std::string, nostd::shared_ptr<opentelemetry::metrics::BoundValueRecorder<T>>>
boundInstruments_;
};
# if defined(_MSC_VER)
# pragma warning(pop)
# endif
} // namespace metrics
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,365 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef ENABLE_METRICS_PREVIEW
# include <map>
# include "opentelemetry/common/macros.h"
# include "opentelemetry/sdk/_metrics/aggregator/counter_aggregator.h"
# include "opentelemetry/sdk/_metrics/aggregator/exact_aggregator.h"
# include "opentelemetry/sdk/_metrics/aggregator/gauge_aggregator.h"
# include "opentelemetry/sdk/_metrics/aggregator/histogram_aggregator.h"
# include "opentelemetry/sdk/_metrics/aggregator/min_max_sum_count_aggregator.h"
# include "opentelemetry/sdk/_metrics/aggregator/sketch_aggregator.h"
# include "opentelemetry/sdk/_metrics/processor.h"
# include "opentelemetry/sdk/_metrics/record.h"
# include "opentelemetry/version.h"
OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace metrics
{
struct KeyStruct
{
std::string name;
std::string description;
std::string labels;
opentelemetry::metrics::InstrumentKind ins_kind;
// constructor
KeyStruct(std::string name,
std::string description,
std::string labels,
opentelemetry::metrics::InstrumentKind ins_kind)
{
this->name = name;
this->description = description;
this->labels = labels;
this->ins_kind = ins_kind;
}
// operator== is required to compare keys in case of hash collision
bool operator==(const KeyStruct &p) const
{
return name == p.name && description == p.description && labels == p.labels &&
ins_kind == p.ins_kind;
}
};
struct KeyStruct_Hash
{
std::size_t operator()(const KeyStruct &keystruct) const
{
std::size_t name_size = keystruct.name.length();
std::size_t desc_size = keystruct.description.length();
std::size_t labels_size = keystruct.labels.length();
std::size_t ins_size = (int)keystruct.ins_kind;
return (name_size ^ desc_size ^ labels_size) + ins_size;
}
};
class UngroupedMetricsProcessor : public MetricsProcessor
{
public:
explicit UngroupedMetricsProcessor(bool stateful);
std::vector<opentelemetry::sdk::metrics::Record> CheckpointSelf() noexcept override;
virtual void FinishedCollection() noexcept override;
virtual void process(opentelemetry::sdk::metrics::Record record) noexcept override;
private:
bool stateful_;
std::unordered_map<KeyStruct, opentelemetry::sdk::metrics::AggregatorVariant, KeyStruct_Hash>
batch_map_;
/**
* get_instrument returns the instrument from the passed in AggregatorVariant. We have to
* unpack the variant then get the instrument from the Aggreagtor.
*/
opentelemetry::metrics::InstrumentKind get_instrument(
opentelemetry::sdk::metrics::AggregatorVariant aggregator)
{
if (nostd::holds_alternative<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<short>>>(
aggregator))
{
return nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<short>>>(aggregator)
->get_instrument_kind();
}
else if (nostd::holds_alternative<
std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<int>>>(aggregator))
{
return nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<int>>>(aggregator)
->get_instrument_kind();
}
else if (nostd::holds_alternative<
std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<float>>>(aggregator))
{
return nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<float>>>(aggregator)
->get_instrument_kind();
}
else if (nostd::holds_alternative<
std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<double>>>(aggregator))
{
return nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<double>>>(
aggregator)
->get_instrument_kind();
}
return opentelemetry::metrics::InstrumentKind::Counter;
}
/**
* aggregator_copy creates a copy of the aggregtor passed through process() for a
* stateful processor. For Sketch, Histogram and Exact we also need to pass in
* additional constructor values
*/
template <typename T>
std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>> aggregator_copy(
std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>> aggregator)
{
auto ins_kind = aggregator->get_instrument_kind();
auto agg_kind = aggregator->get_aggregator_kind();
switch (agg_kind)
{
case opentelemetry::sdk::metrics::AggregatorKind::Counter:
return std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>>(
new opentelemetry::sdk::metrics::CounterAggregator<T>(ins_kind));
case opentelemetry::sdk::metrics::AggregatorKind::MinMaxSumCount:
return std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>>(
new opentelemetry::sdk::metrics::MinMaxSumCountAggregator<T>(ins_kind));
case opentelemetry::sdk::metrics::AggregatorKind::Gauge:
return std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>>(
new opentelemetry::sdk::metrics::GaugeAggregator<T>(ins_kind));
case opentelemetry::sdk::metrics::AggregatorKind::Sketch:
return std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>>(
new opentelemetry::sdk::metrics::SketchAggregator<T>(
ins_kind, aggregator->get_error_bound(), aggregator->get_max_buckets()));
case opentelemetry::sdk::metrics::AggregatorKind::Histogram:
return std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>>(
new opentelemetry::sdk::metrics::HistogramAggregator<T>(ins_kind,
aggregator->get_boundaries()));
case opentelemetry::sdk::metrics::AggregatorKind::Exact:
return std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>>(
new opentelemetry::sdk::metrics::ExactAggregator<T>(
ins_kind, aggregator->get_quant_estimation()));
default:
return std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>>(
new opentelemetry::sdk::metrics::CounterAggregator<T>(ins_kind));
}
};
/**
* aggregator_for will return an Aggregator based off the instrument passed in. This should be
* the function that we assign Aggreagtors for instruments, but is currently unused in our
* pipeline.
*/
template <typename T>
std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>> aggregator_for(
opentelemetry::metrics::InstrumentKind ins_kind)
{
switch (ins_kind)
{
case opentelemetry::metrics::InstrumentKind::Counter:
return std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>>(
new opentelemetry::sdk::metrics::CounterAggregator<T>(ins_kind));
case opentelemetry::metrics::InstrumentKind::UpDownCounter:
return std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>>(
new opentelemetry::sdk::metrics::CounterAggregator<T>(ins_kind));
case opentelemetry::metrics::InstrumentKind::ValueRecorder:
return std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>>(
new opentelemetry::sdk::metrics::MinMaxSumCountAggregator<T>(ins_kind));
case opentelemetry::metrics::InstrumentKind::SumObserver:
return std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>>(
new opentelemetry::sdk::metrics::CounterAggregator<T>(ins_kind));
case opentelemetry::metrics::InstrumentKind::UpDownSumObserver:
return std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>>(
new opentelemetry::sdk::metrics::CounterAggregator<T>(ins_kind));
case opentelemetry::metrics::InstrumentKind::ValueObserver:
return std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>>(
new opentelemetry::sdk::metrics::MinMaxSumCountAggregator<T>(ins_kind));
default:
return std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>>(
new opentelemetry::sdk::metrics::CounterAggregator<T>(ins_kind));
}
};
/**
* merge_aggreagtors takes in two shared pointers to aggregators of the same kind.
* We first need to dynamically cast to the actual Aggregator that is held in the
* Aggregator<T> wrapper. Then we must get the underlying pointer from the shared
* pointer and merge them together.
*/
template <typename T>
void merge_aggregators(std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>> batch_agg,
std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<T>> record_agg)
{
auto agg_kind = batch_agg->get_aggregator_kind();
if (agg_kind == opentelemetry::sdk::metrics::AggregatorKind::Counter)
{
# ifdef OPENTELEMETRY_RTTI_ENABLED
std::shared_ptr<opentelemetry::sdk::metrics::CounterAggregator<T>> temp_batch_agg_counter =
std::dynamic_pointer_cast<opentelemetry::sdk::metrics::CounterAggregator<T>>(batch_agg);
std::shared_ptr<opentelemetry::sdk::metrics::CounterAggregator<T>> temp_record_agg_counter =
std::dynamic_pointer_cast<opentelemetry::sdk::metrics::CounterAggregator<T>>(record_agg);
# else
std::shared_ptr<opentelemetry::sdk::metrics::CounterAggregator<T>> temp_batch_agg_counter =
std::static_pointer_cast<opentelemetry::sdk::metrics::CounterAggregator<T>>(batch_agg);
std::shared_ptr<opentelemetry::sdk::metrics::CounterAggregator<T>> temp_record_agg_counter =
std::static_pointer_cast<opentelemetry::sdk::metrics::CounterAggregator<T>>(record_agg);
# endif
auto temp_batch_agg_raw_counter = temp_batch_agg_counter.get();
auto temp_record_agg_raw_counter = temp_record_agg_counter.get();
temp_batch_agg_raw_counter->merge(*temp_record_agg_raw_counter);
}
else if (agg_kind == opentelemetry::sdk::metrics::AggregatorKind::MinMaxSumCount)
{
# ifdef OPENTELEMETRY_RTTI_ENABLED
std::shared_ptr<opentelemetry::sdk::metrics::MinMaxSumCountAggregator<T>>
temp_batch_agg_mmsc =
std::dynamic_pointer_cast<opentelemetry::sdk::metrics::MinMaxSumCountAggregator<T>>(
batch_agg);
std::shared_ptr<opentelemetry::sdk::metrics::MinMaxSumCountAggregator<T>>
temp_record_agg_mmsc =
std::dynamic_pointer_cast<opentelemetry::sdk::metrics::MinMaxSumCountAggregator<T>>(
record_agg);
# else
std::shared_ptr<opentelemetry::sdk::metrics::MinMaxSumCountAggregator<T>>
temp_batch_agg_mmsc =
std::static_pointer_cast<opentelemetry::sdk::metrics::MinMaxSumCountAggregator<T>>(
batch_agg);
std::shared_ptr<opentelemetry::sdk::metrics::MinMaxSumCountAggregator<T>>
temp_record_agg_mmsc =
std::static_pointer_cast<opentelemetry::sdk::metrics::MinMaxSumCountAggregator<T>>(
record_agg);
# endif
auto temp_batch_agg_raw_mmsc = temp_batch_agg_mmsc.get();
auto temp_record_agg_raw_mmsc = temp_record_agg_mmsc.get();
temp_batch_agg_raw_mmsc->merge(*temp_record_agg_raw_mmsc);
}
else if (agg_kind == opentelemetry::sdk::metrics::AggregatorKind::Gauge)
{
# ifdef OPENTELEMETRY_RTTI_ENABLED
std::shared_ptr<opentelemetry::sdk::metrics::GaugeAggregator<T>> temp_batch_agg_gauge =
std::dynamic_pointer_cast<opentelemetry::sdk::metrics::GaugeAggregator<T>>(batch_agg);
std::shared_ptr<opentelemetry::sdk::metrics::GaugeAggregator<T>> temp_record_agg_gauge =
std::dynamic_pointer_cast<opentelemetry::sdk::metrics::GaugeAggregator<T>>(record_agg);
# else
std::shared_ptr<opentelemetry::sdk::metrics::GaugeAggregator<T>> temp_batch_agg_gauge =
std::static_pointer_cast<opentelemetry::sdk::metrics::GaugeAggregator<T>>(batch_agg);
std::shared_ptr<opentelemetry::sdk::metrics::GaugeAggregator<T>> temp_record_agg_gauge =
std::static_pointer_cast<opentelemetry::sdk::metrics::GaugeAggregator<T>>(record_agg);
# endif
auto temp_batch_agg_raw_gauge = temp_batch_agg_gauge.get();
auto temp_record_agg_raw_gauge = temp_record_agg_gauge.get();
temp_batch_agg_raw_gauge->merge(*temp_record_agg_raw_gauge);
}
else if (agg_kind == opentelemetry::sdk::metrics::AggregatorKind::Sketch)
{
# ifdef OPENTELEMETRY_RTTI_ENABLED
std::shared_ptr<opentelemetry::sdk::metrics::SketchAggregator<T>> temp_batch_agg_sketch =
std::dynamic_pointer_cast<opentelemetry::sdk::metrics::SketchAggregator<T>>(batch_agg);
std::shared_ptr<opentelemetry::sdk::metrics::SketchAggregator<T>> temp_record_agg_sketch =
std::dynamic_pointer_cast<opentelemetry::sdk::metrics::SketchAggregator<T>>(record_agg);
# else
std::shared_ptr<opentelemetry::sdk::metrics::SketchAggregator<T>> temp_batch_agg_sketch =
std::static_pointer_cast<opentelemetry::sdk::metrics::SketchAggregator<T>>(batch_agg);
std::shared_ptr<opentelemetry::sdk::metrics::SketchAggregator<T>> temp_record_agg_sketch =
std::static_pointer_cast<opentelemetry::sdk::metrics::SketchAggregator<T>>(record_agg);
# endif
auto temp_batch_agg_raw_sketch = temp_batch_agg_sketch.get();
auto temp_record_agg_raw_sketch = temp_record_agg_sketch.get();
temp_batch_agg_raw_sketch->merge(*temp_record_agg_raw_sketch);
}
else if (agg_kind == opentelemetry::sdk::metrics::AggregatorKind::Histogram)
{
# ifdef OPENTELEMETRY_RTTI_ENABLED
std::shared_ptr<opentelemetry::sdk::metrics::HistogramAggregator<T>>
temp_batch_agg_histogram =
std::dynamic_pointer_cast<opentelemetry::sdk::metrics::HistogramAggregator<T>>(
batch_agg);
std::shared_ptr<opentelemetry::sdk::metrics::HistogramAggregator<T>>
temp_record_agg_histogram =
std::dynamic_pointer_cast<opentelemetry::sdk::metrics::HistogramAggregator<T>>(
record_agg);
# else
std::shared_ptr<opentelemetry::sdk::metrics::HistogramAggregator<T>>
temp_batch_agg_histogram =
std::static_pointer_cast<opentelemetry::sdk::metrics::HistogramAggregator<T>>(
batch_agg);
std::shared_ptr<opentelemetry::sdk::metrics::HistogramAggregator<T>>
temp_record_agg_histogram =
std::static_pointer_cast<opentelemetry::sdk::metrics::HistogramAggregator<T>>(
record_agg);
# endif
auto temp_batch_agg_raw_histogram = temp_batch_agg_histogram.get();
auto temp_record_agg_raw_histogram = temp_record_agg_histogram.get();
temp_batch_agg_raw_histogram->merge(*temp_record_agg_raw_histogram);
}
else if (agg_kind == opentelemetry::sdk::metrics::AggregatorKind::Exact)
{
# ifdef OPENTELEMETRY_RTTI_ENABLED
std::shared_ptr<opentelemetry::sdk::metrics::ExactAggregator<T>> temp_batch_agg_exact =
std::dynamic_pointer_cast<opentelemetry::sdk::metrics::ExactAggregator<T>>(batch_agg);
std::shared_ptr<opentelemetry::sdk::metrics::ExactAggregator<T>> temp_record_agg_exact =
std::dynamic_pointer_cast<opentelemetry::sdk::metrics::ExactAggregator<T>>(record_agg);
# else
std::shared_ptr<opentelemetry::sdk::metrics::ExactAggregator<T>> temp_batch_agg_exact =
std::static_pointer_cast<opentelemetry::sdk::metrics::ExactAggregator<T>>(batch_agg);
std::shared_ptr<opentelemetry::sdk::metrics::ExactAggregator<T>> temp_record_agg_exact =
std::static_pointer_cast<opentelemetry::sdk::metrics::ExactAggregator<T>>(record_agg);
# endif
auto temp_batch_agg_raw_exact = temp_batch_agg_exact.get();
auto temp_record_agg_raw_exact = temp_record_agg_exact.get();
temp_batch_agg_raw_exact->merge(*temp_record_agg_raw_exact);
}
}
};
} // namespace metrics
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,26 +0,0 @@
# Copyright 2020, OpenTelemetry Authors
#
# 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.
package(default_visibility = ["//visibility:public"])
cc_library(
name = "metrics_deprecated",
srcs = glob(["**/*.cc"]),
hdrs = glob(["**/*.h"]),
include_prefix = "src/_metrics",
deps = [
"//api",
"//sdk:headers",
],
)

View File

@ -1,19 +0,0 @@
add_library(opentelemetry_metrics_deprecated meter_provider.cc meter.cc
ungrouped_processor.cc)
set_target_properties(opentelemetry_metrics_deprecated
PROPERTIES EXPORT_NAME metrics_deprecated)
target_link_libraries(opentelemetry_metrics_deprecated
PUBLIC opentelemetry_common)
target_include_directories(
opentelemetry_metrics_deprecated
PUBLIC "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/sdk/include>")
install(
TARGETS opentelemetry_metrics_deprecated
EXPORT "${PROJECT_NAME}-target"
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})

View File

@ -1,782 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#ifdef ENABLE_METRICS_PREVIEW
# include "opentelemetry/sdk/_metrics/meter.h"
# include "opentelemetry/common/macros.h"
namespace metrics_api = opentelemetry::metrics;
OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace metrics
{
nostd::shared_ptr<metrics_api::Counter<short>> Meter::NewShortCounter(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled)
{
if (!IsValidName(name) || NameAlreadyUsed(name))
{
# if __EXCEPTIONS
throw std::invalid_argument("Invalid Name");
# else
std::terminate();
# endif
}
auto counter = new Counter<short>(name, description, unit, enabled);
auto ptr = std::shared_ptr<metrics_api::Counter<short>>(counter);
metrics_lock_.lock();
short_metrics_.insert(std::make_pair(std::string(name), ptr));
metrics_lock_.unlock();
return nostd::shared_ptr<metrics_api::Counter<short>>(ptr);
}
nostd::shared_ptr<metrics_api::Counter<int>> Meter::NewIntCounter(nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled)
{
if (!IsValidName(name) || NameAlreadyUsed(name))
{
# if __EXCEPTIONS
throw std::invalid_argument("Invalid Name");
# else
std::terminate();
# endif
}
auto counter = new Counter<int>(name, description, unit, enabled);
auto ptr = std::shared_ptr<metrics_api::Counter<int>>(counter);
metrics_lock_.lock();
int_metrics_.insert(std::make_pair(std::string(name), ptr));
metrics_lock_.unlock();
return nostd::shared_ptr<metrics_api::Counter<int>>(ptr);
}
nostd::shared_ptr<metrics_api::Counter<float>> Meter::NewFloatCounter(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled)
{
if (!IsValidName(name) || NameAlreadyUsed(name))
{
# if __EXCEPTIONS
throw std::invalid_argument("Invalid Name");
# else
std::terminate();
# endif
}
auto counter = new Counter<float>(name, description, unit, enabled);
auto ptr = std::shared_ptr<metrics_api::Counter<float>>(counter);
metrics_lock_.lock();
float_metrics_.insert(std::make_pair(std::string(name), ptr));
metrics_lock_.unlock();
return nostd::shared_ptr<metrics_api::Counter<float>>(ptr);
}
nostd::shared_ptr<metrics_api::Counter<double>> Meter::NewDoubleCounter(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled)
{
if (!IsValidName(name) || NameAlreadyUsed(name))
{
# if __EXCEPTIONS
throw std::invalid_argument("Invalid Name");
# else
std::terminate();
# endif
}
auto counter = new Counter<double>(name, description, unit, enabled);
auto ptr = std::shared_ptr<metrics_api::Counter<double>>(counter);
metrics_lock_.lock();
double_metrics_.insert(std::make_pair(std::string(name), ptr));
metrics_lock_.unlock();
return nostd::shared_ptr<metrics_api::Counter<double>>(ptr);
}
nostd::shared_ptr<metrics_api::UpDownCounter<short>> Meter::NewShortUpDownCounter(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled)
{
if (!IsValidName(name) || NameAlreadyUsed(name))
{
# if __EXCEPTIONS
throw std::invalid_argument("Invalid Name");
# else
std::terminate();
# endif
}
auto udcounter = new UpDownCounter<short>(name, description, unit, enabled);
auto ptr = std::shared_ptr<metrics_api::UpDownCounter<short>>(udcounter);
metrics_lock_.lock();
short_metrics_.insert(std::make_pair(std::string(name), ptr));
metrics_lock_.unlock();
return nostd::shared_ptr<metrics_api::UpDownCounter<short>>(ptr);
}
nostd::shared_ptr<metrics_api::UpDownCounter<int>> Meter::NewIntUpDownCounter(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled)
{
if (!IsValidName(name) || NameAlreadyUsed(name))
{
# if __EXCEPTIONS
throw std::invalid_argument("Invalid Name");
# else
std::terminate();
# endif
}
auto udcounter = new UpDownCounter<int>(name, description, unit, enabled);
auto ptr = std::shared_ptr<metrics_api::UpDownCounter<int>>(udcounter);
metrics_lock_.lock();
int_metrics_.insert(std::make_pair(std::string(name), ptr));
metrics_lock_.unlock();
return nostd::shared_ptr<metrics_api::UpDownCounter<int>>(ptr);
}
nostd::shared_ptr<metrics_api::UpDownCounter<float>> Meter::NewFloatUpDownCounter(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled)
{
if (!IsValidName(name) || NameAlreadyUsed(name))
{
# if __EXCEPTIONS
throw std::invalid_argument("Invalid Name");
# else
std::terminate();
# endif
}
auto udcounter = new UpDownCounter<float>(name, description, unit, enabled);
auto ptr = std::shared_ptr<metrics_api::UpDownCounter<float>>(udcounter);
metrics_lock_.lock();
float_metrics_.insert(std::make_pair(std::string(name), ptr));
metrics_lock_.unlock();
return nostd::shared_ptr<metrics_api::UpDownCounter<float>>(ptr);
}
nostd::shared_ptr<metrics_api::UpDownCounter<double>> Meter::NewDoubleUpDownCounter(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled)
{
if (!IsValidName(name) || NameAlreadyUsed(name))
{
# if __EXCEPTIONS
throw std::invalid_argument("Invalid Name");
# else
std::terminate();
# endif
}
auto udcounter = new UpDownCounter<double>(name, description, unit, enabled);
auto ptr = std::shared_ptr<metrics_api::UpDownCounter<double>>(udcounter);
metrics_lock_.lock();
double_metrics_.insert(std::make_pair(std::string(name), ptr));
metrics_lock_.unlock();
return nostd::shared_ptr<metrics_api::UpDownCounter<double>>(ptr);
}
nostd::shared_ptr<metrics_api::ValueRecorder<short>> Meter::NewShortValueRecorder(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled)
{
if (!IsValidName(name) || NameAlreadyUsed(name))
{
# if __EXCEPTIONS
throw std::invalid_argument("Invalid Name");
# else
std::terminate();
# endif
}
auto recorder = new ValueRecorder<short>(name, description, unit, enabled);
auto ptr = std::shared_ptr<metrics_api::ValueRecorder<short>>(recorder);
metrics_lock_.lock();
short_metrics_.insert(std::make_pair(std::string(name), ptr));
metrics_lock_.unlock();
return nostd::shared_ptr<metrics_api::ValueRecorder<short>>(ptr);
}
nostd::shared_ptr<metrics_api::ValueRecorder<int>> Meter::NewIntValueRecorder(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled)
{
if (!IsValidName(name) || NameAlreadyUsed(name))
{
# if __EXCEPTIONS
throw std::invalid_argument("Invalid Name");
# else
std::terminate();
# endif
}
auto recorder = new ValueRecorder<int>(name, description, unit, enabled);
auto ptr = std::shared_ptr<metrics_api::ValueRecorder<int>>(recorder);
metrics_lock_.lock();
int_metrics_.insert(std::make_pair(std::string(name), ptr));
metrics_lock_.unlock();
return nostd::shared_ptr<metrics_api::ValueRecorder<int>>(ptr);
}
nostd::shared_ptr<metrics_api::ValueRecorder<float>> Meter::NewFloatValueRecorder(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled)
{
if (!IsValidName(name) || NameAlreadyUsed(name))
{
# if __EXCEPTIONS
throw std::invalid_argument("Invalid Name");
# else
std::terminate();
# endif
}
auto recorder = new ValueRecorder<float>(name, description, unit, enabled);
auto ptr = std::shared_ptr<metrics_api::ValueRecorder<float>>(recorder);
metrics_lock_.lock();
float_metrics_.insert(std::make_pair(std::string(name), ptr));
metrics_lock_.unlock();
return nostd::shared_ptr<metrics_api::ValueRecorder<float>>(ptr);
}
nostd::shared_ptr<metrics_api::ValueRecorder<double>> Meter::NewDoubleValueRecorder(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled)
{
if (!IsValidName(name) || NameAlreadyUsed(name))
{
# if __EXCEPTIONS
throw std::invalid_argument("Invalid Name");
# else
std::terminate();
# endif
}
auto recorder = new ValueRecorder<double>(name, description, unit, enabled);
auto ptr = std::shared_ptr<metrics_api::ValueRecorder<double>>(recorder);
metrics_lock_.lock();
double_metrics_.insert(std::make_pair(std::string(name), ptr));
metrics_lock_.unlock();
return nostd::shared_ptr<metrics_api::ValueRecorder<double>>(ptr);
}
nostd::shared_ptr<metrics_api::SumObserver<short>> Meter::NewShortSumObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(metrics_api::ObserverResult<short>))
{
if (!IsValidName(name) || NameAlreadyUsed(name))
{
# if __EXCEPTIONS
throw std::invalid_argument("Invalid Name");
# else
std::terminate();
# endif
}
auto sumobs = new SumObserver<short>(name, description, unit, enabled, callback);
auto ptr = std::shared_ptr<metrics_api::SumObserver<short>>(sumobs);
observers_lock_.lock();
short_observers_.insert(std::make_pair(std::string(name), ptr));
observers_lock_.unlock();
return nostd::shared_ptr<metrics_api::SumObserver<short>>(ptr);
}
nostd::shared_ptr<metrics_api::SumObserver<int>> Meter::NewIntSumObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(metrics_api::ObserverResult<int>))
{
if (!IsValidName(name) || NameAlreadyUsed(name))
{
# if __EXCEPTIONS
throw std::invalid_argument("Invalid Name");
# else
std::terminate();
# endif
}
auto sumobs = new SumObserver<int>(name, description, unit, enabled, callback);
auto ptr = std::shared_ptr<metrics_api::SumObserver<int>>(sumobs);
observers_lock_.lock();
int_observers_.insert(std::make_pair(std::string(name), ptr));
observers_lock_.unlock();
return nostd::shared_ptr<metrics_api::SumObserver<int>>(ptr);
}
nostd::shared_ptr<metrics_api::SumObserver<float>> Meter::NewFloatSumObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(metrics_api::ObserverResult<float>))
{
if (!IsValidName(name) || NameAlreadyUsed(name))
{
# if __EXCEPTIONS
throw std::invalid_argument("Invalid Name");
# else
std::terminate();
# endif
}
auto sumobs = new SumObserver<float>(name, description, unit, enabled, callback);
auto ptr = std::shared_ptr<metrics_api::SumObserver<float>>(sumobs);
observers_lock_.lock();
float_observers_.insert(std::make_pair(std::string(name), ptr));
observers_lock_.unlock();
return nostd::shared_ptr<metrics_api::SumObserver<float>>(ptr);
}
nostd::shared_ptr<metrics_api::SumObserver<double>> Meter::NewDoubleSumObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(metrics_api::ObserverResult<double>))
{
if (!IsValidName(name) || NameAlreadyUsed(name))
{
# if __EXCEPTIONS
throw std::invalid_argument("Invalid Name");
# else
std::terminate();
# endif
}
auto sumobs = new SumObserver<double>(name, description, unit, enabled, callback);
auto ptr = std::shared_ptr<metrics_api::SumObserver<double>>(sumobs);
observers_lock_.lock();
double_observers_.insert(std::make_pair(std::string(name), ptr));
observers_lock_.unlock();
return nostd::shared_ptr<metrics_api::SumObserver<double>>(ptr);
}
nostd::shared_ptr<metrics_api::UpDownSumObserver<short>> Meter::NewShortUpDownSumObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(metrics_api::ObserverResult<short>))
{
if (!IsValidName(name) || NameAlreadyUsed(name))
{
# if __EXCEPTIONS
throw std::invalid_argument("Invalid Name");
# else
std::terminate();
# endif
}
auto sumobs = new UpDownSumObserver<short>(name, description, unit, enabled, callback);
auto ptr = std::shared_ptr<metrics_api::UpDownSumObserver<short>>(sumobs);
observers_lock_.lock();
short_observers_.insert(std::make_pair(std::string(name), ptr));
observers_lock_.unlock();
return nostd::shared_ptr<metrics_api::UpDownSumObserver<short>>(ptr);
}
nostd::shared_ptr<metrics_api::UpDownSumObserver<int>> Meter::NewIntUpDownSumObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(metrics_api::ObserverResult<int>))
{
if (!IsValidName(name) || NameAlreadyUsed(name))
{
# if __EXCEPTIONS
throw std::invalid_argument("Invalid Name");
# else
std::terminate();
# endif
}
auto sumobs = new UpDownSumObserver<int>(name, description, unit, enabled, callback);
auto ptr = std::shared_ptr<metrics_api::UpDownSumObserver<int>>(sumobs);
observers_lock_.lock();
int_observers_.insert(std::make_pair(std::string(name), ptr));
observers_lock_.unlock();
return nostd::shared_ptr<metrics_api::UpDownSumObserver<int>>(ptr);
}
nostd::shared_ptr<metrics_api::UpDownSumObserver<float>> Meter::NewFloatUpDownSumObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(metrics_api::ObserverResult<float>))
{
if (!IsValidName(name) || NameAlreadyUsed(name))
{
# if __EXCEPTIONS
throw std::invalid_argument("Invalid Name");
# else
std::terminate();
# endif
}
auto sumobs = new UpDownSumObserver<float>(name, description, unit, enabled, callback);
auto ptr = std::shared_ptr<metrics_api::UpDownSumObserver<float>>(sumobs);
observers_lock_.lock();
float_observers_.insert(std::make_pair(std::string(name), ptr));
observers_lock_.unlock();
return nostd::shared_ptr<metrics_api::UpDownSumObserver<float>>(ptr);
}
nostd::shared_ptr<metrics_api::UpDownSumObserver<double>> Meter::NewDoubleUpDownSumObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(metrics_api::ObserverResult<double>))
{
if (!IsValidName(name) || NameAlreadyUsed(name))
{
# if __EXCEPTIONS
throw std::invalid_argument("Invalid Name");
# else
std::terminate();
# endif
}
auto sumobs = new UpDownSumObserver<double>(name, description, unit, enabled, callback);
auto ptr = std::shared_ptr<metrics_api::UpDownSumObserver<double>>(sumobs);
observers_lock_.lock();
double_observers_.insert(std::make_pair(std::string(name), ptr));
observers_lock_.unlock();
return nostd::shared_ptr<metrics_api::UpDownSumObserver<double>>(ptr);
}
nostd::shared_ptr<metrics_api::ValueObserver<short>> Meter::NewShortValueObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(metrics_api::ObserverResult<short>))
{
if (!IsValidName(name) || NameAlreadyUsed(name))
{
# if __EXCEPTIONS
throw std::invalid_argument("Invalid Name");
# else
std::terminate();
# endif
}
auto sumobs = new ValueObserver<short>(name, description, unit, enabled, callback);
auto ptr = std::shared_ptr<metrics_api::ValueObserver<short>>(sumobs);
observers_lock_.lock();
short_observers_.insert(std::make_pair(std::string(name), ptr));
observers_lock_.unlock();
return nostd::shared_ptr<metrics_api::ValueObserver<short>>(ptr);
}
nostd::shared_ptr<metrics_api::ValueObserver<int>> Meter::NewIntValueObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(metrics_api::ObserverResult<int>))
{
if (!IsValidName(name) || NameAlreadyUsed(name))
{
# if __EXCEPTIONS
throw std::invalid_argument("Invalid Name");
# else
std::terminate();
# endif
}
auto sumobs = new ValueObserver<int>(name, description, unit, enabled, callback);
auto ptr = std::shared_ptr<metrics_api::ValueObserver<int>>(sumobs);
observers_lock_.lock();
int_observers_.insert(std::make_pair(std::string(name), ptr));
observers_lock_.unlock();
return nostd::shared_ptr<metrics_api::ValueObserver<int>>(ptr);
}
nostd::shared_ptr<metrics_api::ValueObserver<float>> Meter::NewFloatValueObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(metrics_api::ObserverResult<float>))
{
if (!IsValidName(name) || NameAlreadyUsed(name))
{
# if __EXCEPTIONS
throw std::invalid_argument("Invalid Name");
# else
std::terminate();
# endif
}
auto sumobs = new ValueObserver<float>(name, description, unit, enabled, callback);
auto ptr = std::shared_ptr<metrics_api::ValueObserver<float>>(sumobs);
observers_lock_.lock();
float_observers_.insert(std::make_pair(std::string(name), ptr));
observers_lock_.unlock();
return nostd::shared_ptr<metrics_api::ValueObserver<float>>(ptr);
}
nostd::shared_ptr<metrics_api::ValueObserver<double>> Meter::NewDoubleValueObserver(
nostd::string_view name,
nostd::string_view description,
nostd::string_view unit,
const bool enabled,
void (*callback)(metrics_api::ObserverResult<double>))
{
if (!IsValidName(name) || NameAlreadyUsed(name))
{
# if __EXCEPTIONS
throw std::invalid_argument("Invalid Name");
# else
std::terminate();
# endif
}
auto sumobs = new ValueObserver<double>(name, description, unit, enabled, callback);
auto ptr = std::shared_ptr<metrics_api::ValueObserver<double>>(sumobs);
observers_lock_.lock();
double_observers_.insert(std::make_pair(std::string(name), ptr));
observers_lock_.unlock();
return nostd::shared_ptr<metrics_api::ValueObserver<double>>(ptr);
}
void Meter::RecordShortBatch(const common::KeyValueIterable &labels,
nostd::span<metrics_api::SynchronousInstrument<short> *> instruments,
nostd::span<const short> values) noexcept
{
for (size_t i = 0; i < instruments.size(); ++i)
{
instruments[i]->update(values[i], labels);
}
}
void Meter::RecordIntBatch(const common::KeyValueIterable &labels,
nostd::span<metrics_api::SynchronousInstrument<int> *> instruments,
nostd::span<const int> values) noexcept
{
for (size_t i = 0; i < instruments.size(); ++i)
{
instruments[i]->update(values[i], labels);
}
}
void Meter::RecordFloatBatch(const common::KeyValueIterable &labels,
nostd::span<metrics_api::SynchronousInstrument<float> *> instruments,
nostd::span<const float> values) noexcept
{
for (size_t i = 0; i < instruments.size(); ++i)
{
instruments[i]->update(values[i], labels);
}
}
void Meter::RecordDoubleBatch(const common::KeyValueIterable &labels,
nostd::span<metrics_api::SynchronousInstrument<double> *> instruments,
nostd::span<const double> values) noexcept
{
for (size_t i = 0; i < instruments.size(); ++i)
{
instruments[i]->update(values[i], labels);
}
}
std::vector<Record> Meter::Collect() noexcept
{
std::vector<Record> records;
CollectMetrics(records);
CollectObservers(records);
return records;
}
// Must cast to sdk::SynchronousInstrument to have access to GetRecords() function
void Meter::CollectMetrics(std::vector<Record> &records)
{
metrics_lock_.lock();
for (auto i = short_metrics_.begin(); i != short_metrics_.end();)
{
CollectSingleSyncInstrument<short>(i, records);
if (i->second.use_count() == 1) // Evaluates to true if user's shared_ptr has been deleted
{
i = short_metrics_.erase(i); // Remove instrument that is no longer accessible
}
else
{
i++;
}
}
for (auto i = int_metrics_.begin(); i != int_metrics_.end();)
{
CollectSingleSyncInstrument<int>(i, records);
if (i->second.use_count() == 1) // Evaluates to true if user's shared_ptr has been deleted
{
i = int_metrics_.erase(i); // Remove instrument that is no longer accessible
}
else
{
i++;
}
}
for (auto i = float_metrics_.begin(); i != float_metrics_.end();)
{
CollectSingleSyncInstrument<float>(i, records);
if (i->second.use_count() == 1) // Evaluates to true if user's shared_ptr has been deleted
{
i = float_metrics_.erase(i); // Remove instrument that is no longer accessible
}
else
{
i++;
}
}
for (auto i = double_metrics_.begin(); i != double_metrics_.end();)
{
CollectSingleSyncInstrument<double>(i, records);
if (i->second.use_count() == 1) // Evaluates to true if user's shared_ptr has been deleted
{
i = double_metrics_.erase(i); // Remove instrument that is no longer accessible
}
else
{
i++;
}
}
metrics_lock_.unlock();
}
template <typename T>
void Meter::CollectSingleSyncInstrument(
typename std::map<std::string, std::shared_ptr<metrics_api::SynchronousInstrument<T>>>::iterator
i,
std::vector<Record> &records)
{
if (!i->second->IsEnabled())
{
i++;
return;
}
# ifdef OPENTELEMETRY_RTTI_ENABLED
auto cast_ptr = std::dynamic_pointer_cast<SynchronousInstrument<T>>(i->second);
# else
auto cast_ptr = std::static_pointer_cast<SynchronousInstrument<T>>(i->second);
# endif
std::vector<Record> new_records = cast_ptr->GetRecords();
records.insert(records.begin(), new_records.begin(), new_records.end());
}
void Meter::CollectObservers(std::vector<Record> &records)
{
observers_lock_.lock();
for (auto i = short_observers_.begin(); i != short_observers_.end();)
{
CollectSingleAsyncInstrument<short>(i, records);
if (i->second.use_count() == 1)
{
i = short_observers_.erase(i);
}
else
{
i++;
}
}
for (auto i = int_observers_.begin(); i != int_observers_.end();)
{
CollectSingleAsyncInstrument<int>(i, records);
if (i->second.use_count() == 1)
{
i = int_observers_.erase(i);
}
else
{
i++;
}
}
for (auto i = float_observers_.begin(); i != float_observers_.end();)
{
CollectSingleAsyncInstrument<float>(i, records);
if (i->second.use_count() == 1)
{
i = float_observers_.erase(i);
}
else
{
i++;
}
}
for (auto i = double_observers_.begin(); i != double_observers_.end();)
{
CollectSingleAsyncInstrument<double>(i, records);
if (i->second.use_count() == 1)
{
i = double_observers_.erase(i);
}
else
{
i++;
}
}
observers_lock_.unlock();
}
template <typename T>
void Meter::CollectSingleAsyncInstrument(
typename std::map<std::string,
std::shared_ptr<metrics_api::AsynchronousInstrument<T>>>::iterator i,
std::vector<Record> &records)
{
if (!i->second->IsEnabled())
{
i++;
return;
}
# ifdef OPENTELEMETRY_RTTI_ENABLED
auto cast_ptr = std::dynamic_pointer_cast<AsynchronousInstrument<T>>(i->second);
# else
auto cast_ptr = std::static_pointer_cast<AsynchronousInstrument<T>>(i->second);
# endif
std::vector<Record> new_records = cast_ptr->GetRecords();
records.insert(records.begin(), new_records.begin(), new_records.end());
}
bool Meter::IsValidName(nostd::string_view name)
{
if (name.empty() || isdigit(name[0]) || isspace(name[0]) || ispunct(name[0]))
return false;
else
{
for (size_t i = 0; i < name.size(); ++i)
{
if (!isalnum(name[i]) && name[i] != '_' && name[i] != '.' && name[i] != '-')
return false;
}
}
return true;
}
bool Meter::NameAlreadyUsed(nostd::string_view name)
{
std::lock_guard<std::mutex> lg_metrics(metrics_lock_);
std::lock_guard<std::mutex> lg_obsevers(observers_lock_);
if (names_.find(std::string(name)) != names_.end())
return true;
else
{
names_.insert(std::string(name));
return false;
}
}
} // namespace metrics
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,29 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#ifdef ENABLE_METRICS_PREVIEW
# include "opentelemetry/sdk/_metrics/meter_provider.h"
OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace metrics
{
namespace nostd = opentelemetry::nostd;
namespace metrics_api = opentelemetry::metrics;
MeterProvider::MeterProvider(std::string library_name, std::string library_version) noexcept
: meter_(new Meter(library_name, library_version))
{}
nostd::shared_ptr<metrics_api::Meter> MeterProvider::GetMeter(
nostd::string_view library_name,
nostd::string_view library_version) noexcept
{
return nostd::shared_ptr<metrics_api::Meter>(meter_);
}
} // namespace metrics
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,178 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#ifdef ENABLE_METRICS_PREVIEW
# include "opentelemetry/sdk/_metrics/ungrouped_processor.h"
OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace metrics
{
UngroupedMetricsProcessor::UngroupedMetricsProcessor(bool stateful)
{
stateful_ = stateful;
}
/**
* CheckpointSelf will return a vector of records to be exported. This function will go through
*aggregators that have been sent through process() and return them as a vector of records.
**/
std::vector<opentelemetry::sdk::metrics::Record>
UngroupedMetricsProcessor::CheckpointSelf() noexcept
{
std::vector<opentelemetry::sdk::metrics::Record> metric_records;
for (auto iter : batch_map_)
{
// Create a record from the held KeyStruct values and add to the Checkpoint
KeyStruct key = iter.first;
opentelemetry::sdk::metrics::Record r{key.name, key.description, key.labels, iter.second};
metric_records.push_back(r);
}
return metric_records;
}
/**
* Once Process is called, FinishCollection() should also be called. In the case of a non stateful
*processor the map will be reset.
**/
void UngroupedMetricsProcessor::FinishedCollection() noexcept
{
if (!stateful_)
{
batch_map_ = {};
}
}
void UngroupedMetricsProcessor::process(opentelemetry::sdk::metrics::Record record) noexcept
{
auto aggregator = record.GetAggregator();
std::string label = record.GetLabels();
std::string name = record.GetName();
std::string description = record.GetDescription();
KeyStruct batch_key = KeyStruct(name, description, label, get_instrument(aggregator));
/**
* If we have already seen this aggregator then we will merge it with the copy that exists in the
*batch_map_ The call to merge here combines only identical records (same key)
**/
if (batch_map_.find(batch_key) != batch_map_.end())
{
auto batch_value = batch_map_[batch_key];
if (nostd::holds_alternative<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<short>>>(
aggregator))
{
auto batch_value_reference_short =
nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<short>>>(batch_value);
auto aggregator_reference_short =
nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<short>>>(aggregator);
merge_aggregators<short>(batch_value_reference_short, aggregator_reference_short);
}
else if (nostd::holds_alternative<
std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<int>>>(aggregator))
{
auto batch_value_reference_int =
nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<int>>>(batch_value);
auto aggregator_reference_int =
nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<int>>>(aggregator);
merge_aggregators<int>(batch_value_reference_int, aggregator_reference_int);
}
else if (nostd::holds_alternative<
std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<float>>>(aggregator))
{
auto batch_value_reference_float =
nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<float>>>(batch_value);
auto aggregator_reference_float =
nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<float>>>(aggregator);
merge_aggregators<float>(batch_value_reference_float, aggregator_reference_float);
}
else if (nostd::holds_alternative<
std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<double>>>(aggregator))
{
auto batch_value_reference_double =
nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<double>>>(batch_value);
auto aggregator_reference_double =
nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<double>>>(aggregator);
merge_aggregators<double>(batch_value_reference_double, aggregator_reference_double);
}
return;
}
/**
* If the processor is stateful and this aggregator has not be seen by the processor yet.
* We create a copy of this aggregator, merge it with the aggregator from the given record.
* Then set this copied aggregator with the batch_key in the batch_map_
**/
if (stateful_)
{
if (nostd::holds_alternative<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<short>>>(
aggregator))
{
auto record_agg_short =
nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<short>>>(aggregator);
auto aggregator_short = aggregator_copy<short>(record_agg_short);
merge_aggregators<short>(aggregator_short, record_agg_short);
batch_map_[batch_key] = aggregator_short;
}
else if (nostd::holds_alternative<
std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<int>>>(aggregator))
{
auto record_agg_int =
nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<int>>>(aggregator);
auto aggregator_int = aggregator_copy<int>(record_agg_int);
merge_aggregators<int>(aggregator_int, record_agg_int);
batch_map_[batch_key] = aggregator_int;
}
else if (nostd::holds_alternative<
std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<float>>>(aggregator))
{
auto record_agg_float =
nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<float>>>(aggregator);
auto aggregator_float = aggregator_copy<float>(record_agg_float);
merge_aggregators<float>(aggregator_float, record_agg_float);
batch_map_[batch_key] = aggregator_float;
}
else if (nostd::holds_alternative<
std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<double>>>(aggregator))
{
auto record_agg_double =
nostd::get<std::shared_ptr<opentelemetry::sdk::metrics::Aggregator<double>>>(aggregator);
auto aggregator_double = aggregator_copy<double>(record_agg_double);
merge_aggregators<double>(aggregator_double, record_agg_double);
batch_map_[batch_key] = aggregator_double;
}
}
else
{
/**
* If the processor is not stateful, we don't need to create a copy of the aggregator, since the
*map will be reset from FinishedCollection().
**/
batch_map_[batch_key] = aggregator;
}
}
} // namespace metrics
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,165 +0,0 @@
cc_test(
name = "controller_test",
srcs = [
"controller_test.cc",
],
tags = [
"metrics",
"test",
],
deps = [
"//exporters/ostream:ostream_metrics_exporter_deprecated",
"//sdk/src/_metrics:metrics_deprecated",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "gauge_aggregator_test",
srcs = [
"gauge_aggregator_test.cc",
],
tags = [
"metrics",
"test",
],
deps = [
"//sdk/src/_metrics:metrics_deprecated",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "min_max_sum_count_aggregator_test",
srcs = [
"min_max_sum_count_aggregator_test.cc",
],
tags = [
"metrics",
"test",
],
deps = [
"//sdk/src/_metrics:metrics_deprecated",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "meter_provider_sdk_test",
srcs = [
"meter_provider_sdk_test.cc",
],
tags = [
"metrics",
"test",
],
deps = [
"//sdk/src/_metrics:metrics_deprecated",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "meter_test",
srcs = [
"meter_test.cc",
],
tags = [
"metrics",
"test",
],
deps = [
"//sdk/src/_metrics:metrics_deprecated",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "counter_aggregator_test",
srcs = [
"counter_aggregator_test.cc",
],
tags = [
"metrics",
"test",
],
deps = [
"//sdk/src/_metrics:metrics_deprecated",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "exact_aggregator_test",
srcs = [
"exact_aggregator_test.cc",
],
tags = [
"metrics",
"test",
],
deps = [
"//sdk/src/_metrics:metrics_deprecated",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "histogram_aggregator_test",
srcs = [
"histogram_aggregator_test.cc",
],
tags = [
"metrics",
"test",
],
deps = [
"//sdk/src/_metrics:metrics_deprecated",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "metric_instrument_test",
srcs = [
"metric_instrument_test.cc",
],
tags = [
"metrics",
"test",
],
deps = [
"//sdk/src/_metrics:metrics_deprecated",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "sketch_aggregator_test",
srcs = [
"sketch_aggregator_test.cc",
],
tags = [
"metrics",
"test",
],
deps = [
"//sdk/src/_metrics:metrics_deprecated",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "ungrouped_processor_test",
srcs = [
"ungrouped_processor_test.cc",
],
tags = [
"metrics",
"test",
],
deps = [
"//sdk/src/_metrics:metrics_deprecated",
"@com_google_googletest//:gtest_main",
],
)

View File

@ -1,21 +0,0 @@
foreach(
testname
meter_provider_sdk_test
gauge_aggregator_test
min_max_sum_count_aggregator_test
exact_aggregator_test
counter_aggregator_test
histogram_aggregator_test
ungrouped_processor_test
meter_test
metric_instrument_test
controller_test)
add_executable(${testname} "${testname}.cc")
target_link_libraries(
${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}
opentelemetry_metrics_deprecated)
gtest_add_tests(
TARGET ${testname}
TEST_PREFIX metrics.
TEST_LIST ${testname})
endforeach()

View File

@ -1,56 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#ifdef ENABLE_METRICS_PREVIEW
# include "opentelemetry/sdk/_metrics/controller.h"
# include "opentelemetry/sdk/_metrics/meter.h"
# include "opentelemetry/sdk/_metrics/ungrouped_processor.h"
# include <gtest/gtest.h>
# include <numeric>
# include <thread>
// #include <chrono>
namespace metrics_api = opentelemetry::metrics;
using namespace opentelemetry::sdk::common;
OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace metrics
{
class DummyExporter : public MetricsExporter
{
ExportResult Export(const std::vector<Record> &records) noexcept
{
return ExportResult::kSuccess;
}
};
TEST(Controller, Constructor)
{
std::shared_ptr<metrics_api::Meter> meter =
std::shared_ptr<metrics_api::Meter>(new Meter("Test"));
PushController alpha(meter, std::unique_ptr<MetricsExporter>(new DummyExporter),
std::shared_ptr<MetricsProcessor>(
new opentelemetry::sdk::metrics::UngroupedMetricsProcessor(false)),
.05);
auto instr = meter->NewIntCounter("test", "none", "none", true);
std::map<std::string, std::string> labels = {{"key", "value"}};
auto labelkv = opentelemetry::common::KeyValueIterableView<decltype(labels)>{labels};
alpha.start();
for (int i = 0; i < 20; i++)
{
instr->add(i, labelkv);
}
alpha.stop();
}
} // namespace metrics
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,120 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#ifdef ENABLE_METRICS_PREVIEW
# include "opentelemetry/sdk/_metrics/aggregator/counter_aggregator.h"
# include <gtest/gtest.h>
# include <numeric>
# include <thread>
namespace metrics_api = opentelemetry::metrics;
OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace metrics
{
TEST(CounterAggregator, NoUpdates)
{
CounterAggregator<int> alpha(metrics_api::InstrumentKind::Counter);
EXPECT_EQ(alpha.get_checkpoint().size(), 1);
EXPECT_EQ(alpha.get_checkpoint()[0], 0);
alpha.checkpoint();
EXPECT_EQ(alpha.get_checkpoint().size(), 1);
EXPECT_EQ(alpha.get_checkpoint()[0], 0);
}
TEST(CounterAggregator, Update)
{
CounterAggregator<int> alpha(metrics_api::InstrumentKind::Counter);
CounterAggregator<int> beta(metrics_api::InstrumentKind::Counter);
for (int i = 0; i < 123456; i++)
{
alpha.update(1);
}
int sum = 0;
for (int i = 0; i < 100; i++)
{
int tmp = std::rand() % 128;
beta.update(tmp);
sum += tmp;
}
EXPECT_EQ(alpha.get_checkpoint()[0], 0); // checkpoint shouldn't change even with updates
EXPECT_EQ(beta.get_checkpoint()[0], 0);
alpha.checkpoint();
beta.checkpoint();
EXPECT_EQ(alpha.get_checkpoint()[0], 123456);
EXPECT_EQ(beta.get_checkpoint()[0], sum);
alpha.update(15);
alpha.checkpoint();
EXPECT_EQ(alpha.get_checkpoint()[0], 15); // reset to 0 after first checkpoint call
}
// callback update function used to test concurrent calls
void incrementingCallback(Aggregator<int> &agg)
{
for (int i = 0; i < 2000000; i++)
{
agg.update(1);
}
}
TEST(CounterAggregator, Concurrency)
{
CounterAggregator<int> alpha(metrics_api::InstrumentKind::Counter);
// spawn new threads that initiate the callback
std::thread first(incrementingCallback, std::ref(alpha));
std::thread second(incrementingCallback, std::ref(alpha));
first.join();
second.join();
alpha.checkpoint();
// race conditions result in values below 2*2000000
EXPECT_EQ(alpha.get_checkpoint()[0], 2 * 2000000);
}
TEST(CounterAggregator, Merge)
{
CounterAggregator<int> alpha(metrics_api::InstrumentKind::Counter);
CounterAggregator<int> beta(metrics_api::InstrumentKind::Counter);
alpha.merge(beta);
alpha.checkpoint();
EXPECT_EQ(alpha.get_checkpoint()[0], 0); // merge with no updates
for (int i = 0; i < 500; i++)
{
alpha.update(1);
}
for (int i = 0; i < 700; i++)
{
beta.update(1);
}
alpha.merge(beta);
alpha.checkpoint();
EXPECT_EQ(alpha.get_checkpoint()[0], 1200);
// HistogramAggregator gamma(metrics_api::BoundInstrumentKind::BoundValueRecorder);
// ASSERT_THROW(alpha.merge(gamma), AggregatorMismatch);
}
} // namespace metrics
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,229 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#include <gtest/gtest.h>
#ifdef ENABLE_METRICS_PREVIEW
# include <thread>
# include "opentelemetry/sdk/_metrics/aggregator/exact_aggregator.h"
using namespace opentelemetry::sdk::metrics;
namespace metrics_api = opentelemetry::metrics;
TEST(ExactAggregatorOrdered, Update)
{
ExactAggregator<int> agg(metrics_api::InstrumentKind::Counter);
std::vector<int> correct;
ASSERT_EQ(agg.get_values(), correct);
agg.update(1);
correct.push_back(1);
ASSERT_EQ(agg.get_values(), std::vector<int>{1});
for (int i = 2; i <= 5; ++i)
{
correct.push_back(i);
agg.update(i);
}
ASSERT_EQ(agg.get_values(), correct);
}
TEST(ExactAggregatorOrdered, Checkpoint)
{
ExactAggregator<int> agg(metrics_api::InstrumentKind::Counter);
std::vector<int> correct;
ASSERT_EQ(agg.get_checkpoint(), correct);
agg.update(1);
correct.push_back(1);
agg.checkpoint();
ASSERT_EQ(agg.get_checkpoint(), correct);
}
TEST(ExactAggregatorOrdered, Merge)
{
ExactAggregator<int> agg1(metrics_api::InstrumentKind::Counter);
ExactAggregator<int> agg2(metrics_api::InstrumentKind::Counter);
agg1.update(1);
agg2.update(2);
agg1.merge(agg2);
std::vector<int> correct{1, 2};
ASSERT_EQ(agg1.get_values(), correct);
}
TEST(ExactAggregatorOrdered, BadMerge)
{
// This verifies that we encounter and error when we try to merge
// two aggregators of different numeric types together.
ExactAggregator<int> agg1(metrics_api::InstrumentKind::Counter);
ExactAggregator<int> agg2(metrics_api::InstrumentKind::ValueRecorder);
agg1.update(1);
agg2.update(2);
agg1.merge(agg2);
// Verify that the aggregators did NOT merge
std::vector<int> correct{1};
ASSERT_EQ(agg1.get_values(), correct);
}
TEST(ExactAggregatorOrdered, Types)
{
// This test verifies that we do not encounter any errors when
// using various numeric types.
ExactAggregator<int> agg_int(metrics_api::InstrumentKind::Counter);
ExactAggregator<long> agg_long(metrics_api::InstrumentKind::Counter);
ExactAggregator<float> agg_float(metrics_api::InstrumentKind::Counter);
ExactAggregator<double> agg_double(metrics_api::InstrumentKind::Counter);
for (int i = 1; i <= 5; ++i)
{
agg_int.update(i);
agg_long.update(i);
}
for (float i = 1.0; i <= 5.0; i += 1)
{
agg_float.update(i);
agg_double.update(i);
}
std::vector<int> correct_int{1, 2, 3, 4, 5};
std::vector<long> correct_long{1, 2, 3, 4, 5};
std::vector<float> correct_float{1.0, 2.0, 3.0, 4.0, 5.0};
std::vector<double> correct_double{1.0, 2.0, 3.0, 4.0, 5.0};
ASSERT_EQ(agg_int.get_values(), correct_int);
ASSERT_EQ(agg_long.get_values(), correct_long);
ASSERT_EQ(agg_float.get_values(), correct_float);
ASSERT_EQ(agg_double.get_values(), correct_double);
}
TEST(ExactAggregatorQuant, Update)
{
ExactAggregator<int> agg(metrics_api::InstrumentKind::Counter, true);
std::vector<int> correct;
ASSERT_EQ(agg.get_values(), correct);
agg.update(1);
correct.push_back(1);
ASSERT_EQ(agg.get_values(), std::vector<int>{1});
for (int i = 2; i <= 5; ++i)
{
correct.push_back(i);
agg.update(i);
}
ASSERT_EQ(agg.get_values(), correct);
}
TEST(ExactAggregatorQuant, Checkpoint)
{
// This test verifies that the aggregator updates correctly when
// quantile estimation is turned on.
ExactAggregator<int> agg(metrics_api::InstrumentKind::Counter, true);
std::vector<int> correct;
ASSERT_EQ(agg.get_checkpoint(), correct);
agg.update(1);
agg.update(0);
agg.update(-1);
// The vector MUST be sorted when checkpointed
correct.push_back(-1);
correct.push_back(0);
correct.push_back(1);
agg.checkpoint();
ASSERT_EQ(agg.get_checkpoint(), correct);
}
TEST(ExactAggregatorQuant, Quantile)
{
// This test verifies that the quantile estimation function returns
// the correct values.
ExactAggregator<int> agg(metrics_api::InstrumentKind::Counter, true);
std::vector<int> tmp{3, 9, 42, 57, 163, 210, 272, 300};
for (int i : tmp)
{
agg.update(i);
}
agg.checkpoint();
ASSERT_EQ(agg.get_quantiles(.25), 42);
ASSERT_EQ(agg.get_quantiles(0.5), 163);
ASSERT_EQ(agg.get_quantiles(0.75), 272);
}
TEST(ExactAggregatorInOrder, Quantile)
{
// This test verifies that if the user has an exact aggregator in "in-order" mode
// an exception will be thrown if they call the quantile() function.
ExactAggregator<int> agg(metrics_api::InstrumentKind::Counter);
std::vector<int> tmp{3, 9, 42, 57, 163, 210, 272, 300};
for (int i : tmp)
{
agg.update(i);
}
agg.checkpoint();
# if __EXCEPTIONS
ASSERT_THROW(agg.get_quantiles(0.5), std::domain_error);
# else
# endif
}
void callback(ExactAggregator<int> &agg)
{
for (int i = 1; i <= 10000; ++i)
{
agg.update(i);
}
}
TEST(ExactAggregatorQuant, Concurrency)
{
// This test checks that the aggregator updates appropriately
// when called in a multi-threaded context.
ExactAggregator<int> agg(metrics_api::InstrumentKind::Counter, true);
std::thread first(&callback, std::ref(agg));
std::thread second(&callback, std::ref(agg));
first.join();
second.join();
std::vector<int> correct;
for (int i = 1; i <= 10000; ++i)
{
correct.push_back(i);
correct.push_back(i);
}
agg.checkpoint();
ASSERT_EQ(agg.get_checkpoint(), correct);
}
#else
TEST(ExactAggregatorQuant, DummyTest)
{
// empty
}
#endif

View File

@ -1,133 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#ifdef ENABLE_METRICS_PREVIEW
# include <gtest/gtest.h>
# include <thread>
# include "opentelemetry/sdk/_metrics/aggregator/gauge_aggregator.h"
using namespace opentelemetry::sdk::metrics;
namespace metrics_api = opentelemetry::metrics;
TEST(GaugeAggregator, Update)
{
// This tests that the aggregator updates the maintained value correctly
// after a call to the update() function.
auto agg = new GaugeAggregator<int>(metrics_api::InstrumentKind::Counter);
// Verify default value
ASSERT_EQ(agg->get_values()[0], 0);
// Verify that the value updates correctly
agg->update(1);
ASSERT_EQ(agg->get_values()[0], 1);
// Verify that the value continually updates correctly
for (int i = 0; i < 10; ++i)
{
agg->update(i);
}
ASSERT_EQ(agg->get_values()[0], 9);
delete agg;
}
TEST(GaugeAggregator, Checkpoint)
{
// This tests that the aggregator correctly updates the
// checkpoint_ value after a call to update() followed
// by a call to checkpoint().
GaugeAggregator<int> agg(metrics_api::InstrumentKind::Counter);
// Verify default checkpoint, before updates
ASSERT_EQ(agg.get_checkpoint()[0], 0);
agg.update(10);
agg.checkpoint();
// Verify that the new checkpoint contains the update value
ASSERT_EQ(agg.get_checkpoint()[0], 10);
}
TEST(GaugeAggregator, Merge)
{
// This tests that the values_ vector is updated correctly after
// two aggregators are merged together.
GaugeAggregator<int> agg1(metrics_api::InstrumentKind::Counter);
GaugeAggregator<int> agg2(metrics_api::InstrumentKind::Counter);
agg1.update(1);
agg2.update(2);
agg1.merge(agg2);
// Verify that the aggregators merged and the value was updated correctly
ASSERT_EQ(agg1.get_values()[0], 2);
}
TEST(GaugeAggregator, BadMerge)
{
// This verifies that we encounter and error when we try to merge
// two aggregators of different numeric types together.
GaugeAggregator<int> agg1(metrics_api::InstrumentKind::Counter);
GaugeAggregator<int> agg2(metrics_api::InstrumentKind::ValueRecorder);
agg1.update(1);
agg2.update(2);
agg1.merge(agg2);
// Verify that the aggregators did NOT merge
std::vector<int> correct{1};
ASSERT_EQ(agg1.get_values(), correct);
}
TEST(GaugeAggregator, Types)
{
// This test verifies that we do not encounter any errors when
// using various numeric types.
GaugeAggregator<int> agg_int(metrics_api::InstrumentKind::Counter);
GaugeAggregator<long> agg_long(metrics_api::InstrumentKind::Counter);
GaugeAggregator<float> agg_float(metrics_api::InstrumentKind::Counter);
GaugeAggregator<double> agg_double(metrics_api::InstrumentKind::Counter);
for (int i = 1; i <= 10; ++i)
{
agg_int.update(i);
agg_long.update(i);
}
for (float i = 1.0; i <= 10.0; i += 1)
{
agg_float.update(i);
agg_double.update(i);
}
ASSERT_EQ(agg_int.get_values()[0], 10);
ASSERT_EQ(agg_long.get_values()[0], 10);
ASSERT_EQ(agg_float.get_values()[0], 10.0);
ASSERT_EQ(agg_double.get_values()[0], 10.0);
}
static void callback(GaugeAggregator<int> &agg)
{
for (int i = 1; i <= 10000; ++i)
{
agg.update(i);
}
}
TEST(GaugeAggregator, Concurrency)
{
// This test checks that the aggregator updates appropriately
// when called in a multi-threaded context.
GaugeAggregator<int> agg(metrics_api::InstrumentKind::Counter);
std::thread first(&callback, std::ref(agg));
std::thread second(&callback, std::ref(agg));
first.join();
second.join();
ASSERT_EQ(agg.get_values()[0], 10000);
}
#endif

View File

@ -1,173 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#ifdef ENABLE_METRICS_PREVIEW
# include "opentelemetry/sdk/_metrics/aggregator/histogram_aggregator.h"
# include <gtest/gtest.h>
# include <iostream>
# include <numeric>
# include <thread>
// #include <chrono>
namespace metrics_api = opentelemetry::metrics;
OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace metrics
{
// Test updating with a uniform set of updates
TEST(Histogram, Uniform)
{
std::vector<double> boundaries{10, 20, 30, 40, 50};
HistogramAggregator<int> alpha(metrics_api::InstrumentKind::Counter, boundaries);
EXPECT_EQ(alpha.get_aggregator_kind(), AggregatorKind::Histogram);
alpha.checkpoint();
EXPECT_EQ(alpha.get_checkpoint().size(), 2);
EXPECT_EQ(alpha.get_counts().size(), 6);
for (int i = 0; i < 60; i++)
{
alpha.update(i);
}
alpha.checkpoint();
EXPECT_EQ(alpha.get_checkpoint()[0], 1770);
EXPECT_EQ(alpha.get_checkpoint()[1], 60);
std::vector<int> correct = {10, 10, 10, 10, 10, 10};
EXPECT_EQ(alpha.get_counts(), correct);
}
// Test updating with a normal distribution
TEST(Histogram, Normal)
{
std::vector<double> boundaries{2, 4, 6, 8, 10, 12};
HistogramAggregator<int> alpha(metrics_api::InstrumentKind::Counter, boundaries);
std::vector<int> vals{1, 3, 3, 5, 5, 5, 7, 7, 7, 7, 9, 9, 9, 11, 11, 13};
for (int i : vals)
{
alpha.update(i);
}
alpha.checkpoint();
EXPECT_EQ(alpha.get_checkpoint()[0], std::accumulate(vals.begin(), vals.end(), 0));
EXPECT_EQ(alpha.get_checkpoint()[1], vals.size());
std::vector<int> correct = {1, 2, 3, 4, 3, 2, 1};
EXPECT_EQ(alpha.get_counts(), correct);
}
TEST(Histogram, Merge)
{
std::vector<double> boundaries{2, 4, 6, 8, 10, 12};
HistogramAggregator<int> alpha(metrics_api::InstrumentKind::Counter, boundaries);
HistogramAggregator<int> beta(metrics_api::InstrumentKind::Counter, boundaries);
std::vector<int> vals{1, 3, 3, 5, 5, 5, 7, 7, 7, 7, 9, 9, 9, 11, 11, 13};
for (int i : vals)
{
alpha.update(i);
}
std::vector<int> otherVals{1, 1, 1, 1, 11, 11, 13, 13, 13, 15};
for (int i : otherVals)
{
beta.update(i);
}
alpha.merge(beta);
alpha.checkpoint();
EXPECT_EQ(alpha.get_checkpoint()[0], std::accumulate(vals.begin(), vals.end(), 0) +
std::accumulate(otherVals.begin(), otherVals.end(), 0));
EXPECT_EQ(alpha.get_checkpoint()[1], vals.size() + otherVals.size());
std::vector<int> correct = {5, 2, 3, 4, 3, 4, 5};
EXPECT_EQ(alpha.get_counts(), correct);
}
// Update callback used to validate multi-threaded performance
void histogramUpdateCallback(Aggregator<int> &agg, std::vector<int> vals)
{
for (int i : vals)
{
agg.update(i);
}
}
int randVal()
{
return rand() % 15;
}
TEST(Histogram, Concurrency)
{
std::vector<double> boundaries{2, 4, 6, 8, 10, 12};
HistogramAggregator<int> alpha(metrics_api::InstrumentKind::Counter, boundaries);
std::vector<int> vals1(1000);
std::generate(vals1.begin(), vals1.end(), randVal);
std::vector<int> vals2(1000);
std::generate(vals2.begin(), vals2.end(), randVal);
std::thread first(histogramUpdateCallback, std::ref(alpha), vals1);
std::thread second(histogramUpdateCallback, std::ref(alpha), vals2);
first.join();
second.join();
HistogramAggregator<int> beta(metrics_api::InstrumentKind::Counter, boundaries);
// Timing harness to compare linear and binary insertion
// auto start = std::chrono::system_clock::now();
for (int i : vals1)
{
beta.update(i);
}
for (int i : vals2)
{
beta.update(i);
}
// auto end = std::chrono::system_clock::now();
// auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start);
// std::cout <<"Update time: " <<elapsed.count() <<std::endl;
alpha.checkpoint();
beta.checkpoint();
EXPECT_EQ(alpha.get_checkpoint(), beta.get_checkpoint());
EXPECT_EQ(alpha.get_counts(), beta.get_counts());
}
# if __EXCEPTIONS
TEST(Histogram, Errors)
{
std::vector<double> boundaries{2, 4, 6, 8, 10, 12};
std::vector<double> boundaries2{1, 4, 6, 8, 10, 12};
std::vector<double> unsortedBoundaries{10, 12, 4, 6, 8};
EXPECT_ANY_THROW(
HistogramAggregator<int> alpha(metrics_api::InstrumentKind::Counter, unsortedBoundaries));
HistogramAggregator<int> beta(metrics_api::InstrumentKind::Counter, boundaries);
HistogramAggregator<int> gamma(metrics_api::InstrumentKind::Counter, boundaries2);
EXPECT_ANY_THROW(beta.merge(gamma));
}
# endif
} // namespace metrics
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,26 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#ifdef ENABLE_METRICS_PREVIEW
# include <gtest/gtest.h>
# include "opentelemetry/sdk/_metrics/meter.h"
# include "opentelemetry/sdk/_metrics/meter_provider.h"
using namespace opentelemetry::sdk::metrics;
TEST(MeterProvider, GetMeter)
{
MeterProvider tf;
auto t1 = tf.GetMeter("test");
auto t2 = tf.GetMeter("test");
auto t3 = tf.GetMeter("different", "1.0.0");
ASSERT_NE(nullptr, t1);
ASSERT_NE(nullptr, t2);
ASSERT_NE(nullptr, t3);
// Should return the same instance each time.
ASSERT_EQ(t1, t2);
ASSERT_EQ(t1, t3);
}
#endif

View File

@ -1,297 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#ifdef ENABLE_METRICS_PREVIEW
# include <gtest/gtest.h>
# include <future>
# include "opentelemetry/sdk/_metrics/meter.h"
using namespace opentelemetry::sdk::metrics;
namespace metrics_api = opentelemetry::metrics;
namespace common = opentelemetry::common;
namespace nostd = opentelemetry::nostd;
OPENTELEMETRY_BEGIN_NAMESPACE
TEST(Meter, CreateSyncInstruments)
{
// Test that there are no errors creating synchronous instruments.
Meter m("Test");
m.NewShortCounter("Test-short-counter", "For testing", "Unitless", true);
m.NewIntCounter("Test-int-counter", "For testing", "Unitless", true);
m.NewFloatCounter("Test-float-counter", "For testing", "Unitless", true);
m.NewDoubleCounter("Test-double-counter", "For testing", "Unitless", true);
m.NewShortUpDownCounter("Test-short-ud-counter", "For testing", "Unitless", true);
m.NewIntUpDownCounter("Test-int-ud-counter", "For testing", "Unitless", true);
m.NewFloatUpDownCounter("Test-float-ud-counter", "For testing", "Unitless", true);
m.NewDoubleUpDownCounter("Test-double-ud-counter", "For testing", "Unitless", true);
m.NewShortValueRecorder("Test-short-recorder", "For testing", "Unitless", true);
m.NewIntValueRecorder("Test-int-recorder", "For testing", "Unitless", true);
m.NewFloatValueRecorder("Test-float-recorder", "For testing", "Unitless", true);
m.NewDoubleValueRecorder("Test-double-recorder", "For testing", "Unitless", true);
}
// Dummy functions for asynchronous instrument constructors
void ShortCallback(metrics_api::ObserverResult<short>) {}
void IntCallback(metrics_api::ObserverResult<int>) {}
void FloatCallback(metrics_api::ObserverResult<float>) {}
void DoubleCallback(metrics_api::ObserverResult<double>) {}
TEST(Meter, CreateAsyncInstruments)
{
// Test that there are no errors when creating asynchronous instruments.
Meter m("Test");
m.NewShortSumObserver("Test-short-sum-obs", "For testing", "Unitless", true, &ShortCallback);
m.NewIntSumObserver("Test-int-sum-obs", "For testing", "Unitless", true, &IntCallback);
m.NewFloatSumObserver("Test-float-sum-obs", "For testing", "Unitless", true, &FloatCallback);
m.NewDoubleSumObserver("Test-double-sum-obs", "For testing", "Unitless", true, &DoubleCallback);
m.NewShortUpDownSumObserver("Test-short-ud-sum-obs", "For testing", "Unitless", true,
&ShortCallback);
m.NewIntUpDownSumObserver("Test-int-ud-sum-obs", "For testing", "Unitless", true, &IntCallback);
m.NewFloatUpDownSumObserver("Test-float-ud-sum-obs", "For testing", "Unitless", true,
&FloatCallback);
m.NewDoubleUpDownSumObserver("Test-double-ud-sum-obs", "For testing", "Unitless", true,
&DoubleCallback);
m.NewShortValueObserver("Test-short-val-obs", "For testing", "Unitless", true, &ShortCallback);
m.NewIntValueObserver("Test-int-val-obs", "For testing", "Unitless", true, &IntCallback);
m.NewFloatValueObserver("Test-float-val-obs", "For testing", "Unitless", true, &FloatCallback);
m.NewDoubleValueObserver("Test-double-val-obs", "For testing", "Unitless", true, &DoubleCallback);
}
TEST(Meter, CollectSyncInstruments)
{
// Verify that the records returned on a call to Collect() are correct for synchronous
// instruments.
Meter m("Test");
ASSERT_EQ(m.Collect().size(), 0);
auto counter = m.NewShortCounter("Test-counter", "For testing", "Unitless", true);
std::map<std::string, std::string> labels = {{"Key", "Value"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
counter->add(1, labelkv);
std::vector<Record> res = m.Collect();
auto agg_var = res[0].GetAggregator();
auto agg = nostd::get<0>(agg_var);
ASSERT_EQ(agg->get_checkpoint()[0], 1);
// Now call add() and Collect() again to ensure that the value in the underlying
// aggregator was reset to the default.
counter->add(10, labelkv);
res = m.Collect();
agg_var = res[0].GetAggregator();
agg = nostd::get<0>(agg_var);
ASSERT_EQ(agg->get_checkpoint()[0], 10);
}
TEST(Meter, CollectDeletedSync)
{
// Verify that calling Collect() after creating a synchronous instrument and destroying
// the return pointer does not result in a segfault.
Meter m("Test");
ASSERT_EQ(m.Collect().size(), 0);
std::map<std::string, std::string> labels = {{"Key", "Value"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
{
auto counter = m.NewShortCounter("Test-counter", "For testing", "Unitless", true);
counter->add(1, labelkv);
} // counter shared_ptr deleted here
std::vector<Record> res = m.Collect();
auto agg_var = res[0].GetAggregator();
auto agg = nostd::get<0>(agg_var);
ASSERT_EQ(agg->get_checkpoint()[0], 1);
}
// Dummy function for asynchronous instrument constructors.
void Callback(metrics_api::ObserverResult<short> result)
{
std::map<std::string, std::string> labels = {{"key", "value"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
result.observe(1, labelkv);
}
TEST(Meter, CollectAsyncInstruments)
{
// Verify that the records returned on a call to Collect() are correct for asynchronous
// instruments.
Meter m("Test");
ASSERT_EQ(m.Collect().size(), 0);
auto sumobs =
m.NewShortSumObserver("Test-counter", "For testing", "Unitless", true, &ShortCallback);
std::map<std::string, std::string> labels = {{"Key", "Value"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
sumobs->observe(1, labelkv);
std::vector<Record> res = m.Collect();
auto agg_var = res[0].GetAggregator();
auto agg = nostd::get<0>(agg_var);
ASSERT_EQ(agg->get_checkpoint()[0], 1);
// Now call observe() and Collect() again to ensure that the value in the underlying
// aggregator was reset to the default.
sumobs->observe(10, labelkv);
res = m.Collect();
agg_var = res[0].GetAggregator();
agg = nostd::get<0>(agg_var);
ASSERT_EQ(agg->get_checkpoint()[0], 10);
}
TEST(Meter, CollectDeletedAsync)
{
// Verify that calling Collect() after creating an asynchronous instrument and destroying
// the return pointer does not result in a segfault.
Meter m("Test");
ASSERT_EQ(m.Collect().size(), 0);
std::map<std::string, std::string> labels = {{"Key", "Value"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
{
auto sumobs = m.NewShortSumObserver("Test-counter", "For testing", "Unitless", true, &Callback);
sumobs->observe(1, labelkv);
} // sumobs shared_ptr deleted here
std::vector<Record> res = m.Collect();
auto agg_var = res[0].GetAggregator();
auto agg = nostd::get<0>(agg_var);
ASSERT_EQ(agg->get_checkpoint()[0], 1);
}
TEST(Meter, RecordBatch)
{
// This tests that RecordBatch appropriately updates the aggregators of the instruments
// passed to the function. Short, int, float, and double data types are tested.
Meter m("Test");
auto scounter = m.NewShortCounter("Test-scounter", "For testing", "Unitless", true);
auto icounter = m.NewIntCounter("Test-icounter", "For testing", "Unitless", true);
auto fcounter = m.NewFloatCounter("Test-fcounter", "For testing", "Unitless", true);
auto dcounter = m.NewDoubleCounter("Test-dcounter", "For testing", "Unitless", true);
std::map<std::string, std::string> labels = {{"Key", "Value"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
metrics_api::SynchronousInstrument<short> *sinstr_arr[] = {scounter.get()};
short svalues_arr[] = {1};
nostd::span<metrics_api::SynchronousInstrument<short> *> sinstrs{sinstr_arr};
nostd::span<const short, 1> svalues{svalues_arr};
m.RecordShortBatch(labelkv, sinstrs, svalues);
std::vector<Record> res = m.Collect();
auto short_agg_var = res[0].GetAggregator();
auto short_agg = nostd::get<0>(short_agg_var);
ASSERT_EQ(short_agg->get_checkpoint()[0], 1);
metrics_api::SynchronousInstrument<int> *iinstr_arr[] = {icounter.get()};
int ivalues_arr[] = {1};
nostd::span<metrics_api::SynchronousInstrument<int> *> iinstrs{iinstr_arr};
nostd::span<const int, 1> ivalues{ivalues_arr};
m.RecordIntBatch(labelkv, iinstrs, ivalues);
res = m.Collect();
auto int_agg_var = res[0].GetAggregator();
auto int_agg = nostd::get<1>(int_agg_var);
ASSERT_EQ(int_agg->get_checkpoint()[0], 1);
metrics_api::SynchronousInstrument<float> *finstr_arr[] = {fcounter.get()};
float fvalues_arr[] = {1.0};
nostd::span<metrics_api::SynchronousInstrument<float> *> finstrs{finstr_arr};
nostd::span<const float, 1> fvalues{fvalues_arr};
m.RecordFloatBatch(labelkv, finstrs, fvalues);
res = m.Collect();
auto float_agg_var = res[0].GetAggregator();
auto float_agg = nostd::get<2>(float_agg_var);
ASSERT_EQ(float_agg->get_checkpoint()[0], 1.0);
metrics_api::SynchronousInstrument<double> *dinstr_arr[] = {dcounter.get()};
double dvalues_arr[] = {1.0};
nostd::span<metrics_api::SynchronousInstrument<double> *> dinstrs{dinstr_arr};
nostd::span<const double, 1> dvalues{dvalues_arr};
m.RecordDoubleBatch(labelkv, dinstrs, dvalues);
res = m.Collect();
auto double_agg_var = res[0].GetAggregator();
auto double_agg = nostd::get<3>(double_agg_var);
ASSERT_EQ(double_agg->get_checkpoint()[0], 1.0);
}
TEST(Meter, DisableCollectSync)
{
Meter m("Test");
std::map<std::string, std::string> labels = {{"Key", "Value"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
auto c = m.NewShortCounter("c", "", "", false);
c->add(1, labelkv);
ASSERT_EQ(m.Collect().size(), 0);
}
TEST(Meter, DisableCollectAsync)
{
Meter m("Test");
std::map<std::string, std::string> labels = {{"Key", "Value"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
auto c = m.NewShortValueObserver("c", "", "", false, &ShortCallback);
c->observe(1, labelkv);
ASSERT_EQ(m.Collect().size(), 0);
}
TEST(MeterStringUtil, IsValid)
{
# if __EXCEPTIONS
Meter m("Test");
ASSERT_ANY_THROW(m.NewShortCounter("", "Empty name is invalid", " ", true));
ASSERT_ANY_THROW(m.NewShortCounter("1a", "Can't begin with a number", " ", true));
ASSERT_ANY_THROW(m.NewShortCounter(".a", "Can't begin with punctuation", " ", true));
ASSERT_ANY_THROW(m.NewShortCounter(" a", "Can't begin with space", " ", true));
ASSERT_ANY_THROW(m.NewShortCounter(
"te^ s=%t", "Only alphanumeric ., -, and _ characters are allowed", " ", true));
# endif
}
TEST(MeterStringUtil, AlreadyExists)
{
# if __EXCEPTIONS
Meter m("Test");
m.NewShortCounter("a", "First instance of instrument named 'a'", "", true);
ASSERT_ANY_THROW(m.NewShortCounter("a", "Second (illegal) instrument named 'a'", "", true));
ASSERT_ANY_THROW(m.NewShortSumObserver("a", "Still illegal even though it is not a short counter",
"", true, &ShortCallback));
# endif
}
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,487 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#ifdef ENABLE_METRICS_PREVIEW
# include <gtest/gtest.h>
# include <cstring>
# include <iostream>
# include <map>
# include <memory>
# include <string>
# include <thread>
# include "opentelemetry/common/macros.h"
# include "opentelemetry/sdk/_metrics/async_instruments.h"
# include "opentelemetry/sdk/_metrics/sync_instruments.h"
namespace metrics_api = opentelemetry::metrics;
# ifdef OPENTELEMETRY_RTTI_ENABLED
# define METRICS_TEST_TYPE_CAST(TO, FROM) dynamic_cast<TO>(FROM)
# else
# define METRICS_TEST_TYPE_CAST(TO, FROM) static_cast<TO>(FROM)
# endif
OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace metrics
{
void ObserverConstructorCallback(metrics_api::ObserverResult<int> result)
{
std::map<std::string, std::string> labels = {{"key", "value"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
result.observe(1, labelkv);
}
TEST(ApiSdkConversion, async)
{
nostd::shared_ptr<metrics_api::AsynchronousInstrument<int>> alpha =
nostd::shared_ptr<metrics_api::AsynchronousInstrument<int>>(
new ValueObserver<int>("ankit", "none", "unitles", true, &ObserverConstructorCallback));
std::map<std::string, std::string> labels = {{"key587", "value264"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
alpha->observe(123456, labelkv);
EXPECT_EQ(METRICS_TEST_TYPE_CAST(AsynchronousInstrument<int> *, alpha.get())
->GetRecords()[0]
.GetLabels(),
"{key587:value264}");
alpha->observe(123456, labelkv);
AggregatorVariant canCollect = METRICS_TEST_TYPE_CAST(AsynchronousInstrument<int> *, alpha.get())
->GetRecords()[0]
.GetAggregator();
EXPECT_EQ(nostd::holds_alternative<std::shared_ptr<Aggregator<short>>>(canCollect), false);
EXPECT_EQ(nostd::holds_alternative<std::shared_ptr<Aggregator<int>>>(canCollect), true);
EXPECT_EQ(nostd::get<std::shared_ptr<Aggregator<int>>>(canCollect)->get_checkpoint()[0], 123456);
}
TEST(IntValueObserver, InstrumentFunctions)
{
ValueObserver<int> alpha("enabled", "no description", "unitless", true,
&ObserverConstructorCallback);
std::map<std::string, std::string> labels = {{"key", "value"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
EXPECT_EQ(alpha.GetName(), "enabled");
EXPECT_EQ(alpha.GetDescription(), "no description");
EXPECT_EQ(alpha.GetUnits(), "unitless");
EXPECT_EQ(alpha.IsEnabled(), true);
EXPECT_EQ(alpha.GetKind(), metrics_api::InstrumentKind::ValueObserver);
alpha.run();
EXPECT_EQ(alpha.boundAggregators_[KvToString(labelkv)]->get_values()[0], 1); // min
}
void ObserverCallback(std::shared_ptr<ValueObserver<int>> in,
int freq,
const common::KeyValueIterable &labels)
{
for (int i = 0; i < freq; i++)
{
in->observe(i, labels);
}
}
void NegObserverCallback(std::shared_ptr<ValueObserver<int>> in,
int freq,
const common::KeyValueIterable &labels)
{
for (int i = 0; i < freq; i++)
{
in->observe(-i, labels);
}
}
TEST(IntValueObserver, StressObserve)
{
std::shared_ptr<ValueObserver<int>> alpha(new ValueObserver<int>(
"enabled", "no description", "unitless", true, &ObserverConstructorCallback));
std::map<std::string, std::string> labels = {{"key", "value"}};
std::map<std::string, std::string> labels1 = {{"key1", "value1"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
auto labelkv1 = common::KeyValueIterableView<decltype(labels1)>{labels1};
std::thread first(ObserverCallback, alpha, 25,
labelkv); // spawn new threads that call the callback
std::thread second(ObserverCallback, alpha, 25, labelkv);
std::thread third(ObserverCallback, alpha, 25, labelkv1);
std::thread fourth(NegObserverCallback, alpha, 25, labelkv1); // negative values
first.join();
second.join();
third.join();
fourth.join();
EXPECT_EQ(alpha->boundAggregators_[KvToString(labelkv)]->get_values()[0], 0); // min
EXPECT_EQ(alpha->boundAggregators_[KvToString(labelkv)]->get_values()[1], 24); // max
EXPECT_EQ(alpha->boundAggregators_[KvToString(labelkv)]->get_values()[2], 600); // sum
EXPECT_EQ(alpha->boundAggregators_[KvToString(labelkv)]->get_values()[3], 50); // count
EXPECT_EQ(alpha->boundAggregators_[KvToString(labelkv1)]->get_values()[0], -24); // min
EXPECT_EQ(alpha->boundAggregators_[KvToString(labelkv1)]->get_values()[1], 24); // max
EXPECT_EQ(alpha->boundAggregators_[KvToString(labelkv1)]->get_values()[2], 0); // sum
EXPECT_EQ(alpha->boundAggregators_[KvToString(labelkv1)]->get_values()[3], 50); // count
}
void SumObserverCallback(std::shared_ptr<SumObserver<int>> in,
int freq,
const common::KeyValueIterable &labels)
{
for (int i = 0; i < freq; i++)
{
in->observe(1, labels);
}
}
TEST(IntSumObserver, StressObserve)
{
std::shared_ptr<SumObserver<int>> alpha(
new SumObserver<int>("test", "none", "unitless", true, &ObserverConstructorCallback));
std::map<std::string, std::string> labels = {{"key", "value"}};
std::map<std::string, std::string> labels1 = {{"key1", "value1"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
auto labelkv1 = common::KeyValueIterableView<decltype(labels1)>{labels1};
std::thread first(SumObserverCallback, alpha, 100000, labelkv);
std::thread second(SumObserverCallback, alpha, 100000, labelkv);
std::thread third(SumObserverCallback, alpha, 300000, labelkv1);
first.join();
second.join();
third.join();
EXPECT_EQ(alpha->boundAggregators_[KvToString(labelkv)]->get_values()[0], 200000);
EXPECT_EQ(alpha->boundAggregators_[KvToString(labelkv1)]->get_values()[0], 300000);
}
void UpDownSumObserverCallback(std::shared_ptr<UpDownSumObserver<int>> in,
int freq,
const common::KeyValueIterable &labels)
{
for (int i = 0; i < freq; i++)
{
in->observe(1, labels);
}
}
void NegUpDownSumObserverCallback(std::shared_ptr<UpDownSumObserver<int>> in,
int freq,
const common::KeyValueIterable &labels)
{
for (int i = 0; i < freq; i++)
{
in->observe(-1, labels);
}
}
TEST(IntUpDownObserver, StressAdd)
{
std::shared_ptr<UpDownSumObserver<int>> alpha(
new UpDownSumObserver<int>("test", "none", "unitless", true, &ObserverConstructorCallback));
std::map<std::string, std::string> labels = {{"key", "value"}};
std::map<std::string, std::string> labels1 = {{"key1", "value1"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
auto labelkv1 = common::KeyValueIterableView<decltype(labels1)>{labels1};
std::thread first(UpDownSumObserverCallback, alpha, 12340,
labelkv); // spawn new threads that call the callback
std::thread second(UpDownSumObserverCallback, alpha, 12340, labelkv);
std::thread third(UpDownSumObserverCallback, alpha, 56780, labelkv1);
std::thread fourth(NegUpDownSumObserverCallback, alpha, 12340, labelkv1); // negative values
first.join();
second.join();
third.join();
fourth.join();
EXPECT_EQ(alpha->boundAggregators_[KvToString(labelkv)]->get_values()[0], 12340 * 2);
EXPECT_EQ(alpha->boundAggregators_[KvToString(labelkv1)]->get_values()[0], 56780 - 12340);
}
TEST(Counter, InstrumentFunctions)
{
Counter<int> alpha("enabled", "no description", "unitless", true);
Counter<double> beta("not enabled", "some description", "units", false);
EXPECT_EQ(static_cast<std::string>(alpha.GetName()), "enabled");
EXPECT_EQ(static_cast<std::string>(alpha.GetDescription()), "no description");
EXPECT_EQ(static_cast<std::string>(alpha.GetUnits()), "unitless");
EXPECT_EQ(alpha.IsEnabled(), true);
EXPECT_EQ(static_cast<std::string>(beta.GetName()), "not enabled");
EXPECT_EQ(static_cast<std::string>(beta.GetDescription()), "some description");
EXPECT_EQ(static_cast<std::string>(beta.GetUnits()), "units");
EXPECT_EQ(beta.IsEnabled(), false);
}
TEST(Counter, Binding)
{
Counter<int> alpha("test", "none", "unitless", true);
std::map<std::string, std::string> labels = {{"key", "value"}};
std::map<std::string, std::string> labels1 = {{"key1", "value1"}};
std::map<std::string, std::string> labels2 = {{"key2", "value2"}, {"key3", "value3"}};
std::map<std::string, std::string> labels3 = {{"key3", "value3"}, {"key2", "value2"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
auto labelkv1 = common::KeyValueIterableView<decltype(labels1)>{labels1};
auto labelkv2 = common::KeyValueIterableView<decltype(labels2)>{labels2};
auto labelkv3 = common::KeyValueIterableView<decltype(labels3)>{labels3};
auto beta = alpha.bindCounter(labelkv);
auto gamma = alpha.bindCounter(labelkv1);
auto delta = alpha.bindCounter(labelkv1);
auto epsilon = alpha.bindCounter(labelkv1);
auto zeta = alpha.bindCounter(labelkv2);
auto eta = alpha.bindCounter(labelkv3);
EXPECT_EQ(beta->get_ref(), 1);
EXPECT_EQ(gamma->get_ref(), 3);
EXPECT_EQ(eta->get_ref(), 2);
delta->unbind();
gamma->unbind();
epsilon->unbind();
EXPECT_EQ(alpha.boundInstruments_[KvToString(labelkv1)]->get_ref(), 0);
EXPECT_EQ(alpha.boundInstruments_.size(), 3);
}
TEST(Counter, getAggsandnewupdate)
{
Counter<int> alpha("test", "none", "unitless", true);
std::map<std::string, std::string> labels = {{"key3", "value3"}, {"key2", "value2"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
auto beta = alpha.bindCounter(labelkv);
beta->add(1);
beta->unbind();
EXPECT_EQ(alpha.boundInstruments_[KvToString(labelkv)]->get_ref(), 0);
EXPECT_EQ(alpha.boundInstruments_.size(), 1);
auto theta = alpha.GetRecords();
EXPECT_EQ(theta.size(), 1);
EXPECT_EQ(theta[0].GetName(), "test");
EXPECT_EQ(theta[0].GetDescription(), "none");
EXPECT_EQ(theta[0].GetLabels(), "{key2:value2,key3:value3}");
}
void CounterCallback(std::shared_ptr<Counter<int>> in,
int freq,
const common::KeyValueIterable &labels)
{
for (int i = 0; i < freq; i++)
{
in->add(1, labels);
}
}
TEST(Counter, StressAdd)
{
std::shared_ptr<Counter<int>> alpha(new Counter<int>("test", "none", "unitless", true));
std::map<std::string, std::string> labels = {{"key", "value"}};
std::map<std::string, std::string> labels1 = {{"key1", "value1"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
auto labelkv1 = common::KeyValueIterableView<decltype(labels1)>{labels1};
std::thread first(CounterCallback, alpha, 1000, labelkv);
std::thread second(CounterCallback, alpha, 1000, labelkv);
std::thread third(CounterCallback, alpha, 3000, labelkv1);
first.join();
second.join();
third.join();
EXPECT_EQ(METRICS_TEST_TYPE_CAST(BoundCounter<int> *,
alpha->boundInstruments_[KvToString(labelkv)].get())
->GetAggregator()
->get_values()[0],
2000);
EXPECT_EQ(METRICS_TEST_TYPE_CAST(BoundCounter<int> *,
alpha->boundInstruments_[KvToString(labelkv1)].get())
->GetAggregator()
->get_values()[0],
3000);
}
void UpDownCounterCallback(std::shared_ptr<UpDownCounter<int>> in,
int freq,
const common::KeyValueIterable &labels)
{
for (int i = 0; i < freq; i++)
{
in->add(1, labels);
}
}
void NegUpDownCounterCallback(std::shared_ptr<UpDownCounter<int>> in,
int freq,
const common::KeyValueIterable &labels)
{
for (int i = 0; i < freq; i++)
{
in->add(-1, labels);
}
}
TEST(IntUpDownCounter, StressAdd)
{
std::shared_ptr<UpDownCounter<int>> alpha(
new UpDownCounter<int>("test", "none", "unitless", true));
std::map<std::string, std::string> labels = {{"key", "value"}};
std::map<std::string, std::string> labels1 = {{"key1", "value1"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
auto labelkv1 = common::KeyValueIterableView<decltype(labels1)>{labels1};
std::thread first(UpDownCounterCallback, alpha, 12340,
labelkv); // spawn new threads that call the callback
std::thread second(UpDownCounterCallback, alpha, 12340, labelkv);
std::thread third(UpDownCounterCallback, alpha, 56780, labelkv1);
std::thread fourth(NegUpDownCounterCallback, alpha, 12340, labelkv1); // negative values
first.join();
second.join();
third.join();
fourth.join();
EXPECT_EQ(METRICS_TEST_TYPE_CAST(BoundUpDownCounter<int> *,
alpha->boundInstruments_[KvToString(labelkv)].get())
->GetAggregator()
->get_values()[0],
12340 * 2);
EXPECT_EQ(METRICS_TEST_TYPE_CAST(BoundUpDownCounter<int> *,
alpha->boundInstruments_[KvToString(labelkv1)].get())
->GetAggregator()
->get_values()[0],
56780 - 12340);
}
void RecorderCallback(std::shared_ptr<ValueRecorder<int>> in,
int freq,
const common::KeyValueIterable &labels)
{
for (int i = 0; i < freq; i++)
{
in->record(i, labels);
}
}
void NegRecorderCallback(std::shared_ptr<ValueRecorder<int>> in,
int freq,
const common::KeyValueIterable &labels)
{
for (int i = 0; i < freq; i++)
{
in->record(-i, labels);
}
}
TEST(IntValueRecorder, StressRecord)
{
std::shared_ptr<ValueRecorder<int>> alpha(
new ValueRecorder<int>("test", "none", "unitless", true));
std::map<std::string, std::string> labels = {{"key", "value"}};
std::map<std::string, std::string> labels1 = {{"key1", "value1"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
auto labelkv1 = common::KeyValueIterableView<decltype(labels1)>{labels1};
std::thread first(RecorderCallback, alpha, 25,
labelkv); // spawn new threads that call the callback
std::thread second(RecorderCallback, alpha, 50, labelkv);
std::thread third(RecorderCallback, alpha, 25, labelkv1);
std::thread fourth(NegRecorderCallback, alpha, 100, labelkv1); // negative values
first.join();
second.join();
third.join();
fourth.join();
EXPECT_EQ(METRICS_TEST_TYPE_CAST(BoundValueRecorder<int> *,
alpha->boundInstruments_[KvToString(labelkv)].get())
->GetAggregator()
->get_values()[0],
0); // min
EXPECT_EQ(METRICS_TEST_TYPE_CAST(BoundValueRecorder<int> *,
alpha->boundInstruments_[KvToString(labelkv)].get())
->GetAggregator()
->get_values()[1],
49); // max
EXPECT_EQ(METRICS_TEST_TYPE_CAST(BoundValueRecorder<int> *,
alpha->boundInstruments_[KvToString(labelkv)].get())
->GetAggregator()
->get_values()[2],
1525); // sum
EXPECT_EQ(METRICS_TEST_TYPE_CAST(BoundValueRecorder<int> *,
alpha->boundInstruments_[KvToString(labelkv)].get())
->GetAggregator()
->get_values()[3],
75); // count
EXPECT_EQ(METRICS_TEST_TYPE_CAST(BoundValueRecorder<int> *,
alpha->boundInstruments_[KvToString(labelkv1)].get())
->GetAggregator()
->get_values()[0],
-99); // min
EXPECT_EQ(METRICS_TEST_TYPE_CAST(BoundValueRecorder<int> *,
alpha->boundInstruments_[KvToString(labelkv1)].get())
->GetAggregator()
->get_values()[1],
24); // max
EXPECT_EQ(METRICS_TEST_TYPE_CAST(BoundValueRecorder<int> *,
alpha->boundInstruments_[KvToString(labelkv1)].get())
->GetAggregator()
->get_values()[2],
-4650); // sum
EXPECT_EQ(METRICS_TEST_TYPE_CAST(BoundValueRecorder<int> *,
alpha->boundInstruments_[KvToString(labelkv1)].get())
->GetAggregator()
->get_values()[3],
125); // count
}
TEST(Instruments, NoUpdateNoRecord)
{
// This test verifies that instruments that have received no updates
// in the last collection period are not made into records for export.
Counter<int> alpha("alpha", "no description", "unitless", true);
std::map<std::string, std::string> labels = {{"key", "value"}};
auto labelkv = common::KeyValueIterableView<decltype(labels)>{labels};
EXPECT_EQ(alpha.GetRecords().size(), 0);
alpha.add(1, labelkv);
EXPECT_EQ(alpha.GetRecords().size(), 1);
UpDownCounter<int> beta("beta", "no description", "unitless", true);
EXPECT_EQ(beta.GetRecords().size(), 0);
beta.add(1, labelkv);
EXPECT_EQ(beta.GetRecords().size(), 1);
ValueRecorder<int> gamma("gamma", "no description", "unitless", true);
EXPECT_EQ(gamma.GetRecords().size(), 0);
gamma.record(1, labelkv);
EXPECT_EQ(gamma.GetRecords().size(), 1);
}
} // namespace metrics
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,209 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#ifdef ENABLE_METRICS_PREVIEW
# include <gtest/gtest.h>
# include <thread>
# include "opentelemetry/sdk/_metrics/aggregator/min_max_sum_count_aggregator.h"
using namespace opentelemetry::sdk::metrics;
namespace metrics_api = opentelemetry::metrics;
TEST(MinMaxSumCountAggregator, Update)
{
// This tests that the aggregator updates the maintained value correctly
// after a call to the update() function.
MinMaxSumCountAggregator<int> agg(metrics_api::InstrumentKind::Counter);
auto value_set = agg.get_values();
ASSERT_EQ(value_set[0], 0);
ASSERT_EQ(value_set[1], 0);
ASSERT_EQ(value_set[2], 0);
ASSERT_EQ(value_set[3], 0);
// 1 + 2 + 3 + ... + 10 = 55
for (int i = 1; i <= 10; ++i)
{
agg.update(i);
}
value_set = agg.get_values();
ASSERT_EQ(value_set[0], 1); // min
ASSERT_EQ(value_set[1], 10); // max
ASSERT_EQ(value_set[2], 55); // sum
ASSERT_EQ(value_set[3], 10); // count
}
TEST(MinMaxSumCountAggregator, FirstUpdate)
{
// This tests that the aggregator appropriately maintains the min and
// max values after a single update call.
MinMaxSumCountAggregator<int> agg(metrics_api::InstrumentKind::Counter);
agg.update(1);
auto value_set = agg.get_values();
ASSERT_EQ(value_set[0], 1); // min
ASSERT_EQ(value_set[1], 1); // max
ASSERT_EQ(value_set[2], 1); // sum
ASSERT_EQ(value_set[3], 1); // count
}
TEST(MinMaxSumCountAggregator, Checkpoint)
{
// This test verifies that the default checkpoint is set correctly
// and that the checkpoint values update correctly after a call
// to the checkpoint() function.
MinMaxSumCountAggregator<int> agg(metrics_api::InstrumentKind::Counter);
// Verify that the default checkpoint is set correctly.
auto checkpoint_set = agg.get_checkpoint();
ASSERT_EQ(checkpoint_set[0], 0); // min
ASSERT_EQ(checkpoint_set[1], 0); // max
ASSERT_EQ(checkpoint_set[2], 0); // sum
ASSERT_EQ(checkpoint_set[3], 0); // count
// 1 + 2 + 3 + ... + 10 = 55
for (int i = 1; i <= 10; ++i)
{
agg.update(i);
}
agg.checkpoint();
// Verify that the checkpoint values were updated.
checkpoint_set = agg.get_checkpoint();
ASSERT_EQ(checkpoint_set[0], 1); // min
ASSERT_EQ(checkpoint_set[1], 10); // max
ASSERT_EQ(checkpoint_set[2], 55); // sum
ASSERT_EQ(checkpoint_set[3], 10); // count
// Verify that the current values were reset to the default state.
auto value_set = agg.get_values();
ASSERT_EQ(value_set[0], 0); // min
ASSERT_EQ(value_set[1], 0); // max
ASSERT_EQ(value_set[2], 0); // sum
ASSERT_EQ(value_set[3], 0); // count
}
TEST(MinMaxSumCountAggregator, Merge)
{
// This tests that the values_ vector is updated correctly after
// two aggregators are merged together.
MinMaxSumCountAggregator<int> agg1(metrics_api::InstrumentKind::Counter);
MinMaxSumCountAggregator<int> agg2(metrics_api::InstrumentKind::Counter);
// 1 + 2 + 3 + ... + 10 = 55
for (int i = 1; i <= 10; ++i)
{
agg1.update(i);
}
// 1 + 2 + 3 + ... + 20 = 210
for (int i = 1; i <= 20; ++i)
{
agg2.update(i);
}
agg1.merge(agg2);
// Verify that the current values were changed by the merge.
auto value_set = agg1.get_values();
ASSERT_EQ(value_set[0], 1); // min
ASSERT_EQ(value_set[1], 20); // max
ASSERT_EQ(value_set[2], 265); // sum
ASSERT_EQ(value_set[3], 30); // count
}
TEST(MinMaxSumCountAggregator, BadMerge)
{
// This verifies that we encounter and error when we try to merge
// two aggregators of different numeric types together.
MinMaxSumCountAggregator<int> agg1(metrics_api::InstrumentKind::Counter);
MinMaxSumCountAggregator<int> agg2(metrics_api::InstrumentKind::ValueRecorder);
agg1.update(1);
agg2.update(2);
agg1.merge(agg2);
// Verify that the values did NOT merge
auto value_set = agg1.get_values();
ASSERT_EQ(value_set[0], 1); // min
ASSERT_EQ(value_set[0], 1); // max
ASSERT_EQ(value_set[0], 1); // sum
ASSERT_EQ(value_set[0], 1); // count
}
TEST(MinMaxSumCountAggregator, Types)
{
// This test verifies that we do not encounter any errors when
// using various numeric types.
MinMaxSumCountAggregator<int> agg_int(metrics_api::InstrumentKind::Counter);
MinMaxSumCountAggregator<long> agg_long(metrics_api::InstrumentKind::Counter);
MinMaxSumCountAggregator<float> agg_float(metrics_api::InstrumentKind::Counter);
MinMaxSumCountAggregator<double> agg_double(metrics_api::InstrumentKind::Counter);
for (int i = 1; i <= 10; ++i)
{
agg_int.update(i);
agg_long.update(i);
}
for (float i = 1.0; i <= 10.0; i += 1)
{
agg_float.update(i);
agg_double.update(i);
}
auto value_set = agg_int.get_values();
ASSERT_EQ(value_set[0], 1); // min
ASSERT_EQ(value_set[1], 10); // max
ASSERT_EQ(value_set[2], 55); // sum
ASSERT_EQ(value_set[3], 10); // count
auto value_set2 = agg_long.get_values();
ASSERT_EQ(value_set[0], 1); // min
ASSERT_EQ(value_set[1], 10); // max
ASSERT_EQ(value_set[2], 55); // sum
ASSERT_EQ(value_set[3], 10); // count
auto value_set3 = agg_float.get_values();
ASSERT_EQ(value_set[0], 1.0); // min
ASSERT_EQ(value_set[1], 10.0); // max
ASSERT_EQ(value_set[2], 55.0); // sum
ASSERT_EQ(value_set[3], 10); // count
auto value_set4 = agg_double.get_values();
ASSERT_EQ(value_set[0], 1.0); // min
ASSERT_EQ(value_set[1], 10.0); // max
ASSERT_EQ(value_set[2], 55.0); // sum
ASSERT_EQ(value_set[3], 10); // count
}
static void callback(MinMaxSumCountAggregator<int> &agg)
{
// 1 + 2 + ... + 10000 = 50005000
for (int i = 1; i <= 10000; ++i)
{
agg.update(i);
}
}
TEST(MinMaxSumCountAggregator, Concurrency)
{
// This test checks that the aggregator updates appropriately
// when called in a multi-threaded context.
MinMaxSumCountAggregator<int> agg(metrics_api::InstrumentKind::Counter);
std::thread first(&callback, std::ref(agg));
std::thread second(&callback, std::ref(agg));
first.join();
second.join();
auto value_set = agg.get_values();
ASSERT_EQ(value_set[0], 1);
ASSERT_EQ(value_set[1], 10000);
ASSERT_EQ(value_set[2], 2 * 50005000);
ASSERT_EQ(value_set[3], 2 * 10000);
}
#endif

View File

@ -1,254 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#ifdef ENABLE_METRICS_PREVIEW
# include "opentelemetry/sdk/_metrics/aggregator/sketch_aggregator.h"
# include <gtest/gtest.h>
# include <iostream>
# include <numeric>
# include <thread>
namespace metrics_api = opentelemetry::metrics;
OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace metrics
{
// Test updating with a uniform set of updates
TEST(Sketch, UniformValues)
{
SketchAggregator<int> alpha(metrics_api::InstrumentKind::ValueRecorder, .000005);
EXPECT_EQ(alpha.get_aggregator_kind(), AggregatorKind::Sketch);
alpha.checkpoint();
EXPECT_EQ(alpha.get_checkpoint().size(), 2);
EXPECT_EQ(alpha.get_boundaries().size(), 0);
EXPECT_EQ(alpha.get_counts().size(), 0);
for (int i = 0; i < 60; i++)
{
alpha.update(i);
}
alpha.checkpoint();
EXPECT_EQ(alpha.get_boundaries().size(), 60);
EXPECT_EQ(alpha.get_counts().size(), 60);
EXPECT_EQ(alpha.get_checkpoint()[0], 1770);
EXPECT_EQ(alpha.get_checkpoint()[1], 60);
}
// Test updating with a normal distribution
TEST(Sketch, NormalValues)
{
SketchAggregator<int> alpha(metrics_api::InstrumentKind::ValueRecorder, .0005);
std::vector<int> vals{1, 3, 3, 5, 5, 5, 7, 7, 7, 7, 9, 9, 9, 11, 11, 13};
for (int i : vals)
{
alpha.update(i);
}
alpha.checkpoint();
EXPECT_EQ(alpha.get_checkpoint()[0], std::accumulate(vals.begin(), vals.end(), 0));
EXPECT_EQ(alpha.get_checkpoint()[1], vals.size());
std::vector<int> correct = {1, 2, 3, 4, 3, 2, 1};
EXPECT_EQ(alpha.get_counts(), correct);
std::vector<double> captured_bounds = alpha.get_boundaries();
for (size_t i = 0; i < captured_bounds.size(); i++)
{
captured_bounds[i] = round(captured_bounds[i]);
}
// It is not guaranteed that bounds are correct once the bucket sizes pass 1000
std::vector<double> correct_bounds = {1, 3, 5, 7, 9, 11, 13};
EXPECT_EQ(captured_bounds, correct_bounds);
}
int randVal()
{
return rand() % 100000;
}
/** Note that in this case, "Large" refers to a number of distinct values which exceed the maximum
* number of allowed buckets.
*/
TEST(Sketch, QuantileSmall)
{
SketchAggregator<int> alpha(metrics_api::InstrumentKind::ValueRecorder, .00005);
std::vector<int> vals1(2048);
std::generate(vals1.begin(), vals1.end(), randVal);
std::vector<int> vals2(2048);
std::generate(vals1.begin(), vals1.end(), randVal);
for (int i : vals1)
{
alpha.update(i);
}
alpha.checkpoint();
std::sort(vals1.begin(), vals1.end());
EXPECT_TRUE(abs(alpha.get_quantiles(.25) - vals1[2048 * .25 - 1]) <= 10);
EXPECT_TRUE(abs(alpha.get_quantiles(.50) - vals1[2048 * .50 - 1]) <= 10);
EXPECT_TRUE(abs(alpha.get_quantiles(.75) - vals1[2048 * .75 - 1]) <= 10);
}
TEST(Sketch, UpdateQuantileLarge)
{
SketchAggregator<int> alpha(metrics_api::InstrumentKind::ValueRecorder, .0005, 7);
std::vector<int> vals{1, 3, 3, 5, 5, 5, 7, 7, 7, 7, 9, 9, 9, 11, 11, 13};
for (int i : vals)
{
alpha.update(i);
}
// This addition should trigger the "1" and "3" buckets to merge
alpha.update(15);
alpha.checkpoint();
std::vector<int> correct = {3, 3, 4, 3, 2, 1, 1};
EXPECT_EQ(alpha.get_counts(), correct);
for (int i : vals)
{
alpha.update(i);
}
alpha.update(15);
alpha.update(17);
alpha.checkpoint();
correct = {6, 4, 3, 2, 1, 1, 1};
EXPECT_EQ(alpha.get_counts(), correct);
}
TEST(Sketch, MergeSmall)
{
SketchAggregator<int> alpha(metrics_api::InstrumentKind::ValueRecorder, .0005);
SketchAggregator<int> beta(metrics_api::InstrumentKind::ValueRecorder, .0005);
std::vector<int> vals{1, 3, 3, 5, 5, 5, 7, 7, 7, 7, 9, 9, 9, 11, 11, 13};
for (int i : vals)
{
alpha.update(i);
}
std::vector<int> otherVals{1, 1, 1, 1, 11, 11, 13, 13, 13, 15};
for (int i : otherVals)
{
beta.update(i);
}
alpha.merge(beta);
alpha.checkpoint();
EXPECT_EQ(alpha.get_checkpoint()[0], std::accumulate(vals.begin(), vals.end(), 0) +
std::accumulate(otherVals.begin(), otherVals.end(), 0));
EXPECT_EQ(alpha.get_checkpoint()[1], vals.size() + otherVals.size());
std::vector<int> correct = {5, 2, 3, 4, 3, 4, 4, 1};
EXPECT_EQ(alpha.get_counts(), correct);
}
TEST(Sketch, MergeLarge)
{
SketchAggregator<int> alpha(metrics_api::InstrumentKind::ValueRecorder, .0005, 7);
SketchAggregator<int> beta(metrics_api::InstrumentKind::ValueRecorder, .0005, 7);
std::vector<int> vals{1, 3, 3, 5, 5, 5, 7, 7, 7, 7, 9, 9, 9, 11, 11, 13};
for (int i : vals)
{
alpha.update(i);
}
std::vector<int> otherVals{1, 1, 1, 1, 11, 11, 13, 13, 13, 15};
for (int i : otherVals)
{
beta.update(i);
}
alpha.merge(beta);
alpha.checkpoint();
EXPECT_EQ(alpha.get_checkpoint()[0], std::accumulate(vals.begin(), vals.end(), 0) +
std::accumulate(otherVals.begin(), otherVals.end(), 0));
EXPECT_EQ(alpha.get_checkpoint()[1], vals.size() + otherVals.size());
std::vector<int> correct = {7, 3, 4, 3, 4, 4, 1};
EXPECT_EQ(alpha.get_counts(), correct);
}
// Update callback used to validate multi-threaded performance
void sketchUpdateCallback(Aggregator<int> &agg, std::vector<int> vals)
{
for (int i : vals)
{
agg.update(i);
}
}
TEST(Sketch, Concurrency)
{
SketchAggregator<int> alpha(metrics_api::InstrumentKind::ValueRecorder, .0005, 20);
std::vector<int> vals1(1000);
std::generate(vals1.begin(), vals1.end(), randVal);
std::vector<int> vals2(1000);
std::generate(vals2.begin(), vals2.end(), randVal);
std::thread first(sketchUpdateCallback, std::ref(alpha), vals1);
std::thread second(sketchUpdateCallback, std::ref(alpha), vals2);
first.join();
second.join();
SketchAggregator<int> beta(metrics_api::InstrumentKind::ValueRecorder, .0005, 20);
for (int i : vals1)
{
beta.update(i);
}
for (int i : vals2)
{
beta.update(i);
}
alpha.checkpoint();
beta.checkpoint();
EXPECT_EQ(alpha.get_checkpoint(), beta.get_checkpoint());
EXPECT_EQ(alpha.get_counts(), beta.get_counts());
EXPECT_EQ(alpha.get_boundaries(), beta.get_boundaries());
}
# if __EXCEPTIONS
TEST(Sketch, Errors)
{
SketchAggregator<int> tol1(metrics_api::InstrumentKind::ValueRecorder, .000005);
SketchAggregator<int> tol2(metrics_api::InstrumentKind::ValueRecorder, .005);
SketchAggregator<int> sz1(metrics_api::InstrumentKind::ValueRecorder, .000005, 2938);
SketchAggregator<int> sz2(metrics_api::InstrumentKind::ValueRecorder, .000005);
EXPECT_ANY_THROW(tol1.merge(tol2));
EXPECT_ANY_THROW(sz1.merge(sz2));
EXPECT_ANY_THROW(tol1.get_quantiles(-.000001));
EXPECT_ANY_THROW(tol1.get_quantiles(1.000001));
}
# endif
} // namespace metrics
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
#endif

View File

@ -1,601 +0,0 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
#ifdef ENABLE_METRICS_PREVIEW
# include "opentelemetry/sdk/_metrics/ungrouped_processor.h"
# include <gtest/gtest.h>
# include "opentelemetry/nostd/shared_ptr.h"
# include "opentelemetry/sdk/_metrics/aggregator/counter_aggregator.h"
namespace metric_sdk = opentelemetry::sdk::metrics;
namespace metrics_api = opentelemetry::metrics;
namespace nostd = opentelemetry::nostd;
/* Test that CheckpointSelf() will return the amount of unique records in it, then
call FinishedCollection and see the map reset */
TEST(UngroupedMetricsProcessor, UngroupedProcessorFinishedCollectionStateless)
{
auto processor = std::unique_ptr<metric_sdk::MetricsProcessor>(
new metric_sdk::UngroupedMetricsProcessor(false));
auto aggregator = std::shared_ptr<metric_sdk::Aggregator<double>>(
new metric_sdk::CounterAggregator<double>(metrics_api::InstrumentKind::Counter));
auto aggregator2 = std::shared_ptr<metric_sdk::Aggregator<double>>(
new metric_sdk::CounterAggregator<double>(metrics_api::InstrumentKind::Counter));
aggregator->update(5.5);
aggregator->checkpoint();
aggregator2->update(500.4);
aggregator2->checkpoint();
metric_sdk::Record r("name", "description", "labels", aggregator);
// Must have different (name, description, label, instrument) to map to
metric_sdk::Record r2("name2", "description2", "labels2", aggregator2);
processor->process(r);
processor->process(r2);
std::vector<metric_sdk::Record> checkpoint = processor->CheckpointSelf();
ASSERT_EQ(checkpoint.size(), 2);
processor->FinishedCollection();
checkpoint = processor->CheckpointSelf();
ASSERT_EQ(checkpoint.size(), 0);
}
/* Test that CheckpointSelf() will return the amount of unique records in it, then
call FinishedCollection and see the map stay the same */
TEST(UngroupedMetricsProcessor, UngroupedProcessorFinishedCollectionStateful)
{
auto processor = std::unique_ptr<metric_sdk::MetricsProcessor>(
new metric_sdk::UngroupedMetricsProcessor(true));
auto aggregator = std::shared_ptr<metric_sdk::Aggregator<double>>(
new metric_sdk::CounterAggregator<double>(metrics_api::InstrumentKind::Counter));
auto aggregator2 = std::shared_ptr<metric_sdk::Aggregator<double>>(
new metric_sdk::CounterAggregator<double>(metrics_api::InstrumentKind::Counter));
aggregator->update(5.5);
aggregator->checkpoint();
aggregator2->update(500.4);
aggregator2->checkpoint();
metric_sdk::Record r("name", "description", "labels", aggregator);
// Must have different (name, description, label, instrument) to map to
metric_sdk::Record r2("name2", "description2", "labels2", aggregator2);
processor->process(r);
processor->process(r2);
std::vector<metric_sdk::Record> checkpoint = processor->CheckpointSelf();
ASSERT_EQ(checkpoint.size(), 2);
processor->FinishedCollection();
ASSERT_EQ(checkpoint.size(), 2);
}
// Test to make sure we keep information from record(short) that goes through process()
TEST(UngroupedMetricsProcessor, UngroupedProcessorKeepsRecordInformationStatelessShort)
{
auto processor = std::unique_ptr<metric_sdk::MetricsProcessor>(
new metric_sdk::UngroupedMetricsProcessor(false));
auto aggregator = std::shared_ptr<metric_sdk::Aggregator<short>>(
new metric_sdk::CounterAggregator<short>(metrics_api::InstrumentKind::Counter));
aggregator->update(4);
aggregator->checkpoint();
metric_sdk::Record r("name", "description", "labels", aggregator);
processor->process(r);
std::vector<metric_sdk::Record> checkpoint = processor->CheckpointSelf();
ASSERT_EQ(checkpoint[0].GetName(), "name");
ASSERT_EQ(checkpoint[0].GetLabels(), "labels");
ASSERT_EQ(checkpoint[0].GetDescription(), "description");
ASSERT_EQ(
nostd::get<std::shared_ptr<metric_sdk::Aggregator<short>>>(checkpoint[0].GetAggregator()),
aggregator);
}
// Test to make sure we keep information from record(int) that goes through process()
TEST(UngroupedMetricsProcessor, UngroupedProcessorKeepsRecordInformationStatelessInt)
{
auto processor = std::unique_ptr<metric_sdk::MetricsProcessor>(
new metric_sdk::UngroupedMetricsProcessor(false));
auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
new metric_sdk::CounterAggregator<int>(metrics_api::InstrumentKind::Counter));
aggregator->update(5);
aggregator->checkpoint();
metric_sdk::Record r("name", "description", "labels", aggregator);
processor->process(r);
std::vector<metric_sdk::Record> checkpoint = processor->CheckpointSelf();
ASSERT_EQ(checkpoint[0].GetName(), "name");
ASSERT_EQ(checkpoint[0].GetLabels(), "labels");
ASSERT_EQ(checkpoint[0].GetDescription(), "description");
ASSERT_EQ(nostd::get<std::shared_ptr<metric_sdk::Aggregator<int>>>(checkpoint[0].GetAggregator()),
aggregator);
}
// Test to make sure we keep information from record(float) that goes through process()
TEST(UngroupedMetricsProcessor, UngroupedProcessorKeepsRecordInformationStatelessFloat)
{
auto processor = std::unique_ptr<metric_sdk::MetricsProcessor>(
new metric_sdk::UngroupedMetricsProcessor(false));
auto aggregator = std::shared_ptr<metric_sdk::Aggregator<float>>(
new metric_sdk::CounterAggregator<float>(metrics_api::InstrumentKind::Counter));
aggregator->update(8.5);
aggregator->checkpoint();
metric_sdk::Record r("name", "description", "labels", aggregator);
processor->process(r);
std::vector<metric_sdk::Record> checkpoint = processor->CheckpointSelf();
ASSERT_EQ(checkpoint[0].GetName(), "name");
ASSERT_EQ(checkpoint[0].GetLabels(), "labels");
ASSERT_EQ(checkpoint[0].GetDescription(), "description");
ASSERT_EQ(
nostd::get<std::shared_ptr<metric_sdk::Aggregator<float>>>(checkpoint[0].GetAggregator()),
aggregator);
}
// Test to make sure we keep information from record(double) that goes through process()
TEST(UngroupedMetricsProcessor, UngroupedProcessorKeepsRecordInformationStatelessDouble)
{
auto processor = std::unique_ptr<metric_sdk::MetricsProcessor>(
new metric_sdk::UngroupedMetricsProcessor(false));
auto aggregator = std::shared_ptr<metric_sdk::Aggregator<double>>(
new metric_sdk::CounterAggregator<double>(metrics_api::InstrumentKind::Counter));
aggregator->update(5.5);
aggregator->checkpoint();
metric_sdk::Record r("name", "description", "labels", aggregator);
processor->process(r);
std::vector<metric_sdk::Record> checkpoint = processor->CheckpointSelf();
ASSERT_EQ(checkpoint[0].GetName(), "name");
ASSERT_EQ(checkpoint[0].GetLabels(), "labels");
ASSERT_EQ(checkpoint[0].GetDescription(), "description");
ASSERT_EQ(
nostd::get<std::shared_ptr<metric_sdk::Aggregator<double>>>(checkpoint[0].GetAggregator()),
aggregator);
}
/**
* The following tests are for the Stateful version of the processor. These tests will make sure
* that when we send the same aggreagtor twice through process(), that the values will be merged.
* We can easily recreate this expected value by making a test aggregator that is updated through
* both process functions but only checkpointed at the end.
*/
TEST(UngroupedMetricsProcessor, UngroupedProcessorKeepsRecordInformationStatefulShort)
{
auto processor = std::unique_ptr<metric_sdk::MetricsProcessor>(
new metric_sdk::UngroupedMetricsProcessor(true));
auto aggregator = std::shared_ptr<metric_sdk::Aggregator<short>>(
new metric_sdk::CounterAggregator<short>(metrics_api::InstrumentKind::Counter));
auto aggregator_test = std::shared_ptr<metric_sdk::Aggregator<short>>(
new metric_sdk::CounterAggregator<short>(metrics_api::InstrumentKind::Counter));
aggregator->update(5);
aggregator_test->update(5);
aggregator->checkpoint();
metric_sdk::Record r("name", "description", "labels", aggregator);
processor->process(r);
std::vector<metric_sdk::Record> checkpoint = processor->CheckpointSelf();
ASSERT_EQ(checkpoint[0].GetName(), "name");
ASSERT_EQ(checkpoint[0].GetLabels(), "labels");
ASSERT_EQ(checkpoint[0].GetDescription(), "description");
ASSERT_EQ(
nostd::get<std::shared_ptr<metric_sdk::Aggregator<short>>>(checkpoint[0].GetAggregator())
->get_checkpoint(),
aggregator->get_checkpoint());
aggregator->update(4);
aggregator_test->update(4);
aggregator->checkpoint();
aggregator_test->checkpoint();
processor->process(r);
std::vector<metric_sdk::Record> checkpoint2 = processor->CheckpointSelf();
ASSERT_EQ(checkpoint2.size(), 1);
ASSERT_EQ(
nostd::get<std::shared_ptr<metric_sdk::Aggregator<short>>>(checkpoint[0].GetAggregator())
->get_checkpoint()[0],
aggregator_test->get_checkpoint()[0]);
}
TEST(UngroupedMetricsProcessor, UngroupedProcessorKeepsRecordInformationStatefulInt)
{
auto processor = std::unique_ptr<metric_sdk::MetricsProcessor>(
new metric_sdk::UngroupedMetricsProcessor(true));
auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
new metric_sdk::CounterAggregator<int>(metrics_api::InstrumentKind::Counter));
auto aggregator_test = std::shared_ptr<metric_sdk::Aggregator<int>>(
new metric_sdk::CounterAggregator<int>(metrics_api::InstrumentKind::Counter));
aggregator->update(5);
aggregator_test->update(5);
aggregator->checkpoint();
metric_sdk::Record r("name", "description", "labels", aggregator);
processor->process(r);
std::vector<metric_sdk::Record> checkpoint = processor->CheckpointSelf();
ASSERT_EQ(checkpoint[0].GetName(), "name");
ASSERT_EQ(checkpoint[0].GetLabels(), "labels");
ASSERT_EQ(checkpoint[0].GetDescription(), "description");
ASSERT_EQ(nostd::get<std::shared_ptr<metric_sdk::Aggregator<int>>>(checkpoint[0].GetAggregator())
->get_checkpoint(),
aggregator->get_checkpoint());
aggregator->update(4);
aggregator_test->update(4);
aggregator->checkpoint();
aggregator_test->checkpoint();
processor->process(r);
std::vector<metric_sdk::Record> checkpoint2 = processor->CheckpointSelf();
ASSERT_EQ(checkpoint2.size(), 1);
ASSERT_EQ(nostd::get<std::shared_ptr<metric_sdk::Aggregator<int>>>(checkpoint[0].GetAggregator())
->get_checkpoint()[0],
aggregator_test->get_checkpoint()[0]);
}
TEST(UngroupedMetricsProcessor, UngroupedProcessorKeepsRecordInformationStatefulFloat)
{
auto processor = std::unique_ptr<metric_sdk::MetricsProcessor>(
new metric_sdk::UngroupedMetricsProcessor(true));
auto aggregator = std::shared_ptr<metric_sdk::Aggregator<float>>(
new metric_sdk::CounterAggregator<float>(metrics_api::InstrumentKind::Counter));
auto aggregator_test = std::shared_ptr<metric_sdk::Aggregator<float>>(
new metric_sdk::CounterAggregator<float>(metrics_api::InstrumentKind::Counter));
aggregator->update(5);
aggregator_test->update(5);
aggregator->checkpoint();
metric_sdk::Record r("name", "description", "labels", aggregator);
processor->process(r);
std::vector<metric_sdk::Record> checkpoint = processor->CheckpointSelf();
ASSERT_EQ(checkpoint[0].GetName(), "name");
ASSERT_EQ(checkpoint[0].GetLabels(), "labels");
ASSERT_EQ(checkpoint[0].GetDescription(), "description");
ASSERT_EQ(
nostd::get<std::shared_ptr<metric_sdk::Aggregator<float>>>(checkpoint[0].GetAggregator())
->get_checkpoint(),
aggregator->get_checkpoint());
aggregator->update(4);
aggregator_test->update(4);
aggregator->checkpoint();
aggregator_test->checkpoint();
processor->process(r);
std::vector<metric_sdk::Record> checkpoint2 = processor->CheckpointSelf();
ASSERT_EQ(checkpoint2.size(), 1);
ASSERT_EQ(
nostd::get<std::shared_ptr<metric_sdk::Aggregator<float>>>(checkpoint[0].GetAggregator())
->get_checkpoint()[0],
aggregator_test->get_checkpoint()[0]);
}
TEST(UngroupedMetricsProcessor, UngroupedProcessorKeepsRecordInformationStatefulDouble)
{
auto processor = std::unique_ptr<metric_sdk::MetricsProcessor>(
new metric_sdk::UngroupedMetricsProcessor(true));
auto aggregator = std::shared_ptr<metric_sdk::Aggregator<double>>(
new metric_sdk::CounterAggregator<double>(metrics_api::InstrumentKind::Counter));
auto aggregator_test = std::shared_ptr<metric_sdk::Aggregator<double>>(
new metric_sdk::CounterAggregator<double>(metrics_api::InstrumentKind::Counter));
aggregator->update(5.5);
aggregator_test->update(5.5);
aggregator->checkpoint();
metric_sdk::Record r("name", "description", "labels", aggregator);
processor->process(r);
std::vector<metric_sdk::Record> checkpoint = processor->CheckpointSelf();
ASSERT_EQ(checkpoint[0].GetName(), "name");
ASSERT_EQ(checkpoint[0].GetLabels(), "labels");
ASSERT_EQ(checkpoint[0].GetDescription(), "description");
ASSERT_EQ(
nostd::get<std::shared_ptr<metric_sdk::Aggregator<double>>>(checkpoint[0].GetAggregator())
->get_checkpoint(),
aggregator->get_checkpoint());
aggregator->update(4.4);
aggregator_test->update(4.4);
aggregator->checkpoint();
aggregator_test->checkpoint();
processor->process(r);
std::vector<metric_sdk::Record> checkpoint2 = processor->CheckpointSelf();
ASSERT_EQ(checkpoint2.size(), 1);
ASSERT_EQ(
nostd::get<std::shared_ptr<metric_sdk::Aggregator<double>>>(checkpoint[0].GetAggregator())
->get_checkpoint()[0],
aggregator_test->get_checkpoint()[0]);
}
TEST(UngroupedMetricsProcessor, UngroupedProcessorKeepsRecordInformationStatefulMinMaxSumCount)
{
auto processor = std::unique_ptr<metric_sdk::MetricsProcessor>(
new metric_sdk::UngroupedMetricsProcessor(true));
auto aggregator = std::shared_ptr<metric_sdk::Aggregator<double>>(
new metric_sdk::MinMaxSumCountAggregator<double>(metrics_api::InstrumentKind::Counter));
auto aggregator2 = std::shared_ptr<metric_sdk::Aggregator<double>>(
new metric_sdk::MinMaxSumCountAggregator<double>(metrics_api::InstrumentKind::Counter));
aggregator->update(1.1);
aggregator->update(2.2);
aggregator2->update(1.1);
aggregator2->update(2.2);
aggregator->checkpoint();
metric_sdk::Record r("name", "description", "labels", aggregator);
processor->process(r);
std::vector<metric_sdk::Record> checkpoint = processor->CheckpointSelf();
ASSERT_EQ(checkpoint[0].GetName(), "name");
ASSERT_EQ(checkpoint[0].GetLabels(), "labels");
ASSERT_EQ(checkpoint[0].GetDescription(), "description");
ASSERT_EQ(
nostd::get<std::shared_ptr<metric_sdk::Aggregator<double>>>(checkpoint[0].GetAggregator())
->get_checkpoint(),
aggregator->get_checkpoint());
aggregator->update(5.5);
aggregator2->update(5.5);
aggregator->checkpoint();
aggregator2->checkpoint();
processor->process(r);
std::vector<metric_sdk::Record> checkpoint2 = processor->CheckpointSelf();
ASSERT_EQ(checkpoint2.size(), 1);
ASSERT_EQ(
nostd::get<std::shared_ptr<metric_sdk::Aggregator<double>>>(checkpoint2[0].GetAggregator())
->get_checkpoint(),
aggregator2->get_checkpoint());
}
TEST(UngroupedMetricsProcessor, UngroupedProcessorKeepsRecordInformationStatefulGauge)
{
auto processor = std::unique_ptr<metric_sdk::MetricsProcessor>(
new metric_sdk::UngroupedMetricsProcessor(true));
auto aggregator = std::shared_ptr<metric_sdk::Aggregator<double>>(
new metric_sdk::GaugeAggregator<double>(metrics_api::InstrumentKind::Counter));
aggregator->update(1.1);
aggregator->update(2.2);
aggregator->checkpoint();
metric_sdk::Record r("name", "description", "labels", aggregator);
processor->process(r);
std::vector<metric_sdk::Record> checkpoint = processor->CheckpointSelf();
ASSERT_EQ(checkpoint[0].GetName(), "name");
ASSERT_EQ(checkpoint[0].GetLabels(), "labels");
ASSERT_EQ(checkpoint[0].GetDescription(), "description");
ASSERT_EQ(
nostd::get<std::shared_ptr<metric_sdk::Aggregator<double>>>(checkpoint[0].GetAggregator())
->get_checkpoint(),
aggregator->get_checkpoint());
aggregator->update(5.4);
aggregator->checkpoint();
processor->process(r);
std::vector<metric_sdk::Record> checkpoint2 = processor->CheckpointSelf();
ASSERT_EQ(checkpoint2.size(), 1);
ASSERT_EQ(
nostd::get<std::shared_ptr<metric_sdk::Aggregator<double>>>(checkpoint2[0].GetAggregator())
->get_checkpoint(),
aggregator->get_checkpoint());
}
TEST(UngroupedMetricsProcessor, UngroupedProcessorKeepsRecordInformationStatefulExact)
{
auto processor = std::unique_ptr<metric_sdk::MetricsProcessor>(
new metric_sdk::UngroupedMetricsProcessor(true));
auto aggregator = std::shared_ptr<metric_sdk::Aggregator<double>>(
new metric_sdk::ExactAggregator<double>(metrics_api::InstrumentKind::Counter, false));
auto aggregator2 = std::shared_ptr<metric_sdk::Aggregator<double>>(
new metric_sdk::ExactAggregator<double>(metrics_api::InstrumentKind::Counter, false));
aggregator->update(1.1);
aggregator->update(2.2);
aggregator2->update(1.1);
aggregator2->update(2.2);
aggregator->checkpoint();
metric_sdk::Record r("name", "description", "labels", aggregator);
processor->process(r);
std::vector<metric_sdk::Record> checkpoint = processor->CheckpointSelf();
ASSERT_EQ(checkpoint[0].GetName(), "name");
ASSERT_EQ(checkpoint[0].GetLabels(), "labels");
ASSERT_EQ(checkpoint[0].GetDescription(), "description");
ASSERT_EQ(
nostd::get<std::shared_ptr<metric_sdk::Aggregator<double>>>(checkpoint[0].GetAggregator())
->get_checkpoint(),
aggregator->get_checkpoint());
aggregator->update(5.4);
aggregator2->update(5.4);
aggregator->checkpoint();
aggregator2->checkpoint();
processor->process(r);
std::vector<metric_sdk::Record> checkpoint2 = processor->CheckpointSelf();
ASSERT_EQ(checkpoint2.size(), 1);
ASSERT_EQ(
nostd::get<std::shared_ptr<metric_sdk::Aggregator<double>>>(checkpoint2[0].GetAggregator())
->get_checkpoint(),
aggregator2->get_checkpoint());
}
TEST(UngroupedMetricsProcessor, UngroupedProcessorKeepsRecordInformationStatefulHistogram)
{
auto processor = std::unique_ptr<metric_sdk::MetricsProcessor>(
new metric_sdk::UngroupedMetricsProcessor(true));
std::vector<double> boundaries{10, 20, 30, 40, 50};
auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
new metric_sdk::HistogramAggregator<int>(metrics_api::InstrumentKind::Counter, boundaries));
auto aggregator2 = std::shared_ptr<metric_sdk::Aggregator<int>>(
new metric_sdk::HistogramAggregator<int>(metrics_api::InstrumentKind::Counter, boundaries));
for (int i = 0; i < 60; i++)
{
aggregator->update(i);
aggregator2->update(i);
}
aggregator->checkpoint();
metric_sdk::Record r("name", "description", "labels", aggregator);
processor->process(r);
std::vector<metric_sdk::Record> checkpoint = processor->CheckpointSelf();
ASSERT_EQ(checkpoint[0].GetName(), "name");
ASSERT_EQ(checkpoint[0].GetLabels(), "labels");
ASSERT_EQ(checkpoint[0].GetDescription(), "description");
ASSERT_EQ(nostd::get<std::shared_ptr<metric_sdk::Aggregator<int>>>(checkpoint[0].GetAggregator())
->get_boundaries(),
aggregator->get_boundaries());
ASSERT_EQ(nostd::get<std::shared_ptr<metric_sdk::Aggregator<int>>>(checkpoint[0].GetAggregator())
->get_counts(),
aggregator->get_counts());
for (int i = 0; i < 60; i++)
{
aggregator->update(i);
aggregator2->update(i);
}
aggregator->checkpoint();
aggregator2->checkpoint();
processor->process(r);
std::vector<metric_sdk::Record> checkpoint2 = processor->CheckpointSelf();
ASSERT_EQ(checkpoint2.size(), 1);
ASSERT_EQ(checkpoint2[0].GetName(), "name");
ASSERT_EQ(checkpoint2[0].GetLabels(), "labels");
ASSERT_EQ(checkpoint2[0].GetDescription(), "description");
ASSERT_EQ(nostd::get<std::shared_ptr<metric_sdk::Aggregator<int>>>(checkpoint2[0].GetAggregator())
->get_boundaries(),
aggregator->get_boundaries());
ASSERT_EQ(nostd::get<std::shared_ptr<metric_sdk::Aggregator<int>>>(checkpoint2[0].GetAggregator())
->get_counts(),
aggregator2->get_counts());
ASSERT_EQ(nostd::get<std::shared_ptr<metric_sdk::Aggregator<int>>>(checkpoint2[0].GetAggregator())
->get_checkpoint(),
aggregator2->get_checkpoint());
}
TEST(UngroupedMetricsProcessor, UngroupedProcessorKeepsRecordInformationStatefulSketch)
{
auto processor = std::unique_ptr<metric_sdk::MetricsProcessor>(
new metric_sdk::UngroupedMetricsProcessor(true));
auto aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
new metric_sdk::SketchAggregator<int>(metrics_api::InstrumentKind::Counter, .00005));
auto test_aggregator = std::shared_ptr<metric_sdk::Aggregator<int>>(
new metric_sdk::SketchAggregator<int>(metrics_api::InstrumentKind::Counter, .00005));
for (int i = 0; i < 60; i++)
{
aggregator->update(i);
test_aggregator->update(i);
}
aggregator->checkpoint();
metric_sdk::Record r("name", "description", "labels", aggregator);
processor->process(r);
std::vector<metric_sdk::Record> checkpoint = processor->CheckpointSelf();
ASSERT_EQ(checkpoint[0].GetName(), "name");
ASSERT_EQ(checkpoint[0].GetLabels(), "labels");
ASSERT_EQ(checkpoint[0].GetDescription(), "description");
ASSERT_EQ(nostd::get<std::shared_ptr<metric_sdk::Aggregator<int>>>(checkpoint[0].GetAggregator())
->get_boundaries(),
aggregator->get_boundaries());
ASSERT_EQ(nostd::get<std::shared_ptr<metric_sdk::Aggregator<int>>>(checkpoint[0].GetAggregator())
->get_counts(),
aggregator->get_counts());
for (int i = 0; i < 60; i++)
{
aggregator->update(i);
test_aggregator->update(i);
}
aggregator->checkpoint();
test_aggregator->checkpoint();
processor->process(r);
std::vector<metric_sdk::Record> checkpoint2 = processor->CheckpointSelf();
ASSERT_EQ(checkpoint2[0].GetName(), "name");
ASSERT_EQ(checkpoint2[0].GetLabels(), "labels");
ASSERT_EQ(checkpoint2[0].GetDescription(), "description");
ASSERT_EQ(nostd::get<std::shared_ptr<metric_sdk::Aggregator<int>>>(checkpoint2[0].GetAggregator())
->get_boundaries(),
test_aggregator->get_boundaries());
ASSERT_EQ(nostd::get<std::shared_ptr<metric_sdk::Aggregator<int>>>(checkpoint2[0].GetAggregator())
->get_counts(),
test_aggregator->get_counts());
ASSERT_EQ(nostd::get<std::shared_ptr<metric_sdk::Aggregator<int>>>(checkpoint2[0].GetAggregator())
->get_checkpoint(),
test_aggregator->get_checkpoint());
}
#endif