Skip to content

Commit

Permalink
Add metric counters to track sensor data in the AddSensorDataBatchHan…
Browse files Browse the repository at this point in the history
…dler class (#1338)

Adds additional metrics to track incoming sensor and local slam result data in Prometheus.
  • Loading branch information
jkammerl authored and wally-the-cartographer committed Jul 30, 2018
1 parent a3c9e9f commit 537b2d6
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "cartographer/cloud/internal/map_builder_context_interface.h"
#include "cartographer/cloud/proto/map_builder_service.pb.h"
#include "cartographer/mapping/local_slam_result_data.h"
#include "cartographer/metrics/counter.h"
#include "cartographer/sensor/internal/dispatchable.h"
#include "cartographer/sensor/timed_point_cloud_data.h"
#include "google/protobuf/empty.pb.h"
Expand All @@ -29,6 +30,10 @@ namespace cartographer {
namespace cloud {
namespace handlers {

metrics::Family<metrics::Counter>*
AddSensorDataBatchHandler::counter_metrics_family_ =
metrics::Family<metrics::Counter>::Null();

void AddSensorDataBatchHandler::OnRequest(
const proto::AddSensorDataBatchRequest& request) {
for (const proto::SensorData& sensor_data : request.sensor_data()) {
Expand All @@ -42,6 +47,9 @@ void AddSensorDataBatchHandler::OnRequest(
Finish(::grpc::Status(::grpc::NOT_FOUND, "Unknown trajectory"));
return;
}
ClientMetrics* const metrics =
GetOrCreateClientMetrics(sensor_data.sensor_metadata().client_id(),
sensor_data.sensor_metadata().trajectory_id());
switch (sensor_data.sensor_data_case()) {
case proto::SensorData::kOdometryData:
GetUnsynchronizedContext<MapBuilderContextInterface>()
Expand All @@ -50,13 +58,15 @@ void AddSensorDataBatchHandler::OnRequest(
sensor::MakeDispatchable(
sensor_data.sensor_metadata().sensor_id(),
sensor::FromProto(sensor_data.odometry_data())));
metrics->odometry_sensor_counter->Increment();
break;
case proto::SensorData::kImuData:
GetUnsynchronizedContext<MapBuilderContextInterface>()
->EnqueueSensorData(sensor_data.sensor_metadata().trajectory_id(),
sensor::MakeDispatchable(
sensor_data.sensor_metadata().sensor_id(),
sensor::FromProto(sensor_data.imu_data())));
metrics->imu_sensor_counter->Increment();
break;
case proto::SensorData::kTimedPointCloudData:
GetUnsynchronizedContext<MapBuilderContextInterface>()
Expand All @@ -65,6 +75,7 @@ void AddSensorDataBatchHandler::OnRequest(
sensor::MakeDispatchable(
sensor_data.sensor_metadata().sensor_id(),
sensor::FromProto(sensor_data.timed_point_cloud_data())));
metrics->timed_point_cloud_counter->Increment();
break;
case proto::SensorData::kFixedFramePoseData:
GetUnsynchronizedContext<MapBuilderContextInterface>()
Expand All @@ -73,6 +84,7 @@ void AddSensorDataBatchHandler::OnRequest(
sensor::MakeDispatchable(
sensor_data.sensor_metadata().sensor_id(),
sensor::FromProto(sensor_data.fixed_frame_pose_data())));
metrics->fixed_frame_pose_counter->Increment();
break;
case proto::SensorData::kLandmarkData:
GetUnsynchronizedContext<MapBuilderContextInterface>()
Expand All @@ -81,12 +93,14 @@ void AddSensorDataBatchHandler::OnRequest(
sensor::MakeDispatchable(
sensor_data.sensor_metadata().sensor_id(),
sensor::FromProto(sensor_data.landmark_data())));
metrics->landmark_counter->Increment();
break;
case proto::SensorData::kLocalSlamResultData:
GetContext<MapBuilderContextInterface>()->EnqueueLocalSlamResultData(
sensor_data.sensor_metadata().trajectory_id(),
sensor_data.sensor_metadata().sensor_id(),
sensor_data.local_slam_result_data());
metrics->local_slam_result_counter->Increment();
break;
default:
LOG(FATAL) << "Unknown sensor data type: "
Expand All @@ -96,6 +110,54 @@ void AddSensorDataBatchHandler::OnRequest(
Send(absl::make_unique<google::protobuf::Empty>());
}

void AddSensorDataBatchHandler::RegisterMetrics(
metrics::FamilyFactory* family_factory) {
counter_metrics_family_ = family_factory->NewCounterFamily(
"cartographer_sensor_data_total", "Sensor data received");
}

AddSensorDataBatchHandler::ClientMetrics*
AddSensorDataBatchHandler::GetOrCreateClientMetrics(
const std::string& client_id, int trajectory_id) {
const std::string map_key = client_id + std::to_string(trajectory_id);
auto client_metric_map_itr = client_metric_map_.find(map_key);
if (client_metric_map_itr != client_metric_map_.end()) {
return client_metric_map_itr->second.get();
}

LOG(INFO) << "Create metrics handler for client: " << client_id;
auto new_metrics = absl::make_unique<ClientMetrics>();
new_metrics->odometry_sensor_counter = counter_metrics_family_->Add(
{{"client_id", client_id},
{"trajectory_id", std::to_string(trajectory_id)},
{"sensor", "odometry"}});
new_metrics->imu_sensor_counter = counter_metrics_family_->Add(
{{"client_id", client_id},
{"trajectory_id", std::to_string(trajectory_id)},
{"sensor", "imu"}});
new_metrics->fixed_frame_pose_counter = counter_metrics_family_->Add(
{{"client_id", client_id},
{"trajectory_id", std::to_string(trajectory_id)},
{"sensor", "fixed_frame_pose"}});
new_metrics->landmark_counter = counter_metrics_family_->Add(
{{"client_id", client_id},
{"trajectory_id", std::to_string(trajectory_id)},
{"sensor", "landmark"}});
new_metrics->local_slam_result_counter = counter_metrics_family_->Add(
{{"client_id", client_id},
{"trajectory_id", std::to_string(trajectory_id)},
{"sensor", "local_slam_result"}});
new_metrics->timed_point_cloud_counter = counter_metrics_family_->Add(
{{"client_id", client_id},
{"trajectory_id", std::to_string(trajectory_id)},
{"sensor", "timed_point_cloud"}});

// Obtain pointer before ownership is transferred.
auto* new_metrics_ptr = new_metrics.get();
client_metric_map_[map_key] = std::move(new_metrics);
return new_metrics_ptr;
}

} // namespace handlers
} // namespace cloud
} // namespace cartographer
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,13 @@
#ifndef CARTOGRAPHER_CLOUD_INTERNAL_HANDLERS_ADD_SENSOR_DATA_BATCH_HANDLER_H
#define CARTOGRAPHER_CLOUD_INTERNAL_HANDLERS_ADD_SENSOR_DATA_BATCH_HANDLER_H

#include <memory>
#include <string>

#include "async_grpc/rpc_handler.h"
#include "cartographer/cloud/proto/map_builder_service.pb.h"
#include "cartographer/metrics/counter.h"
#include "cartographer/metrics/family_factory.h"
#include "google/protobuf/empty.pb.h"

namespace cartographer {
Expand All @@ -34,6 +39,28 @@ class AddSensorDataBatchHandler
: public async_grpc::RpcHandler<AddSensorDataBatchSignature> {
public:
void OnRequest(const proto::AddSensorDataBatchRequest& request) override;

static void RegisterMetrics(metrics::FamilyFactory* family_factory);

private:
struct ClientMetrics {
metrics::Counter* odometry_sensor_counter;
metrics::Counter* imu_sensor_counter;
metrics::Counter* timed_point_cloud_counter;
metrics::Counter* fixed_frame_pose_counter;
metrics::Counter* landmark_counter;
metrics::Counter* local_slam_result_counter;
};

ClientMetrics* GetOrCreateClientMetrics(const std::string& client_id,
int trajectory_id);

static cartographer::metrics::Family<metrics::Counter>*
counter_metrics_family_;

// Holds individual metrics for each client.
std::unordered_map<std::string, std::unique_ptr<ClientMetrics>>
client_metric_map_;
};

} // namespace handlers
Expand Down
45 changes: 30 additions & 15 deletions cartographer/cloud/metrics/prometheus/family_factory.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
* limitations under the License.
*/

#include <unordered_map>

#include "cartographer/cloud/metrics/prometheus/family_factory.h"

#include "absl/memory/memory.h"
Expand All @@ -30,6 +32,23 @@ namespace {

using BucketBoundaries = ::cartographer::metrics::Histogram::BucketBoundaries;

// Creates or looks up already existing objects from a wrapper map.
template <typename WrapperMap,
typename ObjectPtr = typename WrapperMap::key_type,
typename Wrapper = typename WrapperMap::mapped_type::element_type>
Wrapper* GetOrCreateWrapper(ObjectPtr object_ptr, WrapperMap* wrapper_map,
std::mutex* wrapper_mutex) {
std::lock_guard<std::mutex> lock(*wrapper_mutex);
auto wrappers_itr = wrapper_map->find(object_ptr);
if (wrappers_itr == wrapper_map->end()) {
auto wrapper = absl::make_unique<Wrapper>(object_ptr);
auto* ptr = wrapper.get();
(*wrapper_map)[object_ptr] = std::unique_ptr<Wrapper>(std::move(wrapper));
return ptr;
}
return wrappers_itr->second.get();
}

class Counter : public ::cartographer::metrics::Counter {
public:
explicit Counter(::prometheus::Counter* prometheus)
Expand All @@ -51,15 +70,14 @@ class CounterFamily

Counter* Add(const std::map<std::string, std::string>& labels) override {
::prometheus::Counter* counter = &prometheus_->Add(labels);
auto wrapper = absl::make_unique<Counter>(counter);
auto* ptr = wrapper.get();
wrappers_.emplace_back(std::move(wrapper));
return ptr;
return GetOrCreateWrapper<>(counter, &wrappers_, &wrappers_mutex_);
}

private:
::prometheus::Family<::prometheus::Counter>* prometheus_;
std::vector<std::unique_ptr<Counter>> wrappers_;
std::mutex wrappers_mutex_;
std::unordered_map<::prometheus::Counter*, std::unique_ptr<Counter>>
wrappers_;
};

class Gauge : public ::cartographer::metrics::Gauge {
Expand All @@ -84,15 +102,13 @@ class GaugeFamily

Gauge* Add(const std::map<std::string, std::string>& labels) override {
::prometheus::Gauge* gauge = &prometheus_->Add(labels);
auto wrapper = absl::make_unique<Gauge>(gauge);
auto* ptr = wrapper.get();
wrappers_.emplace_back(std::move(wrapper));
return ptr;
return GetOrCreateWrapper<>(gauge, &wrappers_, &wrappers_mutex_);
}

private:
::prometheus::Family<::prometheus::Gauge>* prometheus_;
std::vector<std::unique_ptr<Gauge>> wrappers_;
std::mutex wrappers_mutex_;
std::unordered_map<::prometheus::Gauge*, std::unique_ptr<Gauge>> wrappers_;
};

class Histogram : public ::cartographer::metrics::Histogram {
Expand All @@ -115,15 +131,14 @@ class HistogramFamily : public ::cartographer::metrics::Family<

Histogram* Add(const std::map<std::string, std::string>& labels) override {
::prometheus::Histogram* histogram = &prometheus_->Add(labels, boundaries_);
auto wrapper = absl::make_unique<Histogram>(histogram);
auto* ptr = wrapper.get();
wrappers_.emplace_back(std::move(wrapper));
return ptr;
return GetOrCreateWrapper<>(histogram, &wrappers_, &wrappers_mutex_);
}

private:
::prometheus::Family<::prometheus::Histogram>* prometheus_;
std::vector<std::unique_ptr<Histogram>> wrappers_;
std::mutex wrappers_mutex_;
std::unordered_map<::prometheus::Histogram*, std::unique_ptr<Histogram>>
wrappers_;
const BucketBoundaries boundaries_;
};

Expand Down
19 changes: 18 additions & 1 deletion cartographer/metrics/family_factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,31 @@
namespace cartographer {
namespace metrics {

template <typename MetricType>
class NullFamily;

template <typename MetricType>
class Family {
public:
public: // Family instance that does nothing. Safe for use in static
// initializers.
static Family<MetricType>* Null() {
static NullFamily<MetricType> null_family;
return &null_family;
}

virtual ~Family() = default;

virtual MetricType* Add(const std::map<std::string, std::string>& labels) = 0;
};

template <typename MetricType>
class NullFamily : public Family<MetricType> {
public:
MetricType* Add(const std::map<std::string, std::string>& labels) override {
return MetricType::Null();
}
};

class FamilyFactory {
public:
virtual ~FamilyFactory() = default;
Expand Down

0 comments on commit 537b2d6

Please sign in to comment.