Skip to content
This repository was archived by the owner on Jul 31, 2023. It is now read-only.

Commit 1bbde06

Browse files
authored
Stackdriver stats: resource must uniquely identify a timeseries. (#389)
- Don't add the opencensus_task label when a non-default MonitoredResource is present. - Refactor exporter code to reduce duplication of effort.
1 parent 8d26a64 commit 1bbde06

4 files changed

Lines changed: 176 additions & 165 deletions

File tree

opencensus/exporters/stats/stackdriver/internal/stackdriver_exporter.cc

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ class Handler : public ::opencensus::stats::StatsExporter::Handler {
6161
// Returns true if the view has already been registered or registration is
6262
// successful, and false if the registration fails or the name has already
6363
// been registered with different parameters.
64-
bool MaybeRegisterView(const opencensus::stats::ViewDescriptor& descriptor)
65-
EXCLUSIVE_LOCKS_REQUIRED(mu_);
64+
bool MaybeRegisterView(const opencensus::stats::ViewDescriptor& descriptor,
65+
bool add_task_label) EXCLUSIVE_LOCKS_REQUIRED(mu_);
6666

6767
const StackdriverOptions opts_;
6868
mutable absl::Mutex mu_;
@@ -103,13 +103,35 @@ void Handler::ExportViewData(
103103
absl::MutexLock l(&mu_);
104104
std::vector<google::monitoring::v3::TimeSeries> time_series;
105105
for (const auto& datum : data) {
106-
if (!MaybeRegisterView(datum.first)) {
107-
continue;
106+
const opencensus::stats::ViewDescriptor& descriptor = datum.first;
107+
const std::string metric_type =
108+
MakeType(opts_.metric_name_prefix, descriptor.name());
109+
const google::api::MonitoredResource* monitored_resource_for_view =
110+
MonitoredResourceForView(descriptor, opts_.monitored_resource,
111+
opts_.per_metric_monitored_resource);
112+
113+
const bool is_known_custom_metric = IsKnownCustomMetric(metric_type);
114+
115+
// If this is a custom metric, add the opencensus_task label so that
116+
// different processes produce different timeseries instead of colliding.
117+
//
118+
// However, if there is a non-default MonitoredResource for this view, it
119+
// must already uniquely identify the timeseries, so don't add the
120+
// opencensus_task label.
121+
const bool add_task_label =
122+
is_known_custom_metric && (monitored_resource_for_view == nullptr);
123+
124+
// Builtin metrics are already defined, skip registration.
125+
if (is_known_custom_metric) {
126+
// If the view can't be registered, skip it.
127+
if (!MaybeRegisterView(descriptor, add_task_label)) {
128+
continue;
129+
}
108130
}
109-
const auto view_time_series =
110-
MakeTimeSeries(opts_.metric_name_prefix, opts_.monitored_resource,
111-
opts_.per_metric_monitored_resource, datum.first,
112-
datum.second, opts_.opencensus_task);
131+
132+
const auto view_time_series = MakeTimeSeries(
133+
opts_.metric_name_prefix, monitored_resource_for_view, descriptor,
134+
/*data=*/datum.second, add_task_label, opts_.opencensus_task);
113135
time_series.insert(time_series.end(), view_time_series.begin(),
114136
view_time_series.end());
115137
}
@@ -156,7 +178,7 @@ void Handler::ExportViewData(
156178
}
157179

158180
bool Handler::MaybeRegisterView(
159-
const opencensus::stats::ViewDescriptor& descriptor) {
181+
const opencensus::stats::ViewDescriptor& descriptor, bool add_task_label) {
160182
const auto& it = registered_descriptors_.find(descriptor.name());
161183
if (it != registered_descriptors_.end()) {
162184
if (it->second != descriptor) {
@@ -168,16 +190,10 @@ bool Handler::MaybeRegisterView(
168190
return true;
169191
}
170192

171-
const std::string metric_type =
172-
MakeType(opts_.metric_name_prefix, descriptor.name());
173-
if (!IsKnownCustomMetric(metric_type)) {
174-
// Builtin metrics are already defined, skip the CreateMetricDescriptor RPC.
175-
return true;
176-
}
177193
auto request = google::monitoring::v3::CreateMetricDescriptorRequest();
178194
request.set_name(opts_.project_id);
179195
SetMetricDescriptor(opts_.project_id, opts_.metric_name_prefix, descriptor,
180-
request.mutable_metric_descriptor());
196+
add_task_label, request.mutable_metric_descriptor());
181197
::grpc::ClientContext context;
182198
context.set_deadline(absl::ToChronoTime(absl::Now() + opts_.rpc_deadline));
183199
google::api::MetricDescriptor response;

opencensus/exporters/stats/stackdriver/internal/stackdriver_utils.cc

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -162,18 +162,31 @@ bool IsKnownCustomMetric(absl::string_view metric_type) {
162162
absl::StartsWith(metric_type, "external.googleapis.com/");
163163
}
164164

165+
const google::api::MonitoredResource* MonitoredResourceForView(
166+
const opencensus::stats::ViewDescriptor& view_descriptor,
167+
const google::api::MonitoredResource& monitored_resource,
168+
const std::unordered_map<std::string, google::api::MonitoredResource>&
169+
per_metric_monitored_resource) {
170+
auto iter = per_metric_monitored_resource.find(view_descriptor.name());
171+
if (iter != per_metric_monitored_resource.end()) {
172+
return &iter->second;
173+
} else if (monitored_resource.type().empty()) {
174+
return nullptr;
175+
} else {
176+
return &monitored_resource;
177+
}
178+
}
179+
165180
void SetMetricDescriptor(
166181
absl::string_view project_name, absl::string_view metric_name_prefix,
167182
const opencensus::stats::ViewDescriptor& view_descriptor,
168-
google::api::MetricDescriptor* metric_descriptor) {
183+
bool add_task_label, google::api::MetricDescriptor* metric_descriptor) {
169184
metric_descriptor->set_name(
170185
MakeName(project_name, metric_name_prefix, view_descriptor.name()));
171186
const std::string metric_type =
172187
MakeType(metric_name_prefix, view_descriptor.name());
173188
metric_descriptor->set_type(metric_type);
174-
if (IsKnownCustomMetric(metric_type)) {
175-
// Custom metrics use this label so that different processes produce
176-
// different timeseries instead of colliding.
189+
if (add_task_label) {
177190
SetOpenCensusTaskLabelDescriptor(metric_descriptor->add_labels());
178191
}
179192
for (const auto& tag_key : view_descriptor.columns()) {
@@ -194,24 +207,19 @@ void SetMetricDescriptor(
194207

195208
std::vector<google::monitoring::v3::TimeSeries> MakeTimeSeries(
196209
absl::string_view metric_name_prefix,
197-
const google::api::MonitoredResource& monitored_resource,
198-
const std::unordered_map<std::string, google::api::MonitoredResource>&
199-
per_metric_monitored_resource,
210+
const google::api::MonitoredResource* monitored_resource_for_view,
200211
const opencensus::stats::ViewDescriptor& view_descriptor,
201-
const opencensus::stats::ViewData& data,
212+
const opencensus::stats::ViewData& data, bool add_task_label,
202213
absl::string_view opencensus_task) {
203214
// Set values that are common across all the rows.
204215
auto base_time_series = google::monitoring::v3::TimeSeries();
205216
const std::string metric_type =
206217
MakeType(metric_name_prefix, view_descriptor.name());
207218
base_time_series.mutable_metric()->set_type(metric_type);
208-
auto iter = per_metric_monitored_resource.find(view_descriptor.name());
209-
if (iter != per_metric_monitored_resource.end()) {
210-
*base_time_series.mutable_resource() = iter->second;
211-
} else if (monitored_resource.type().empty()) {
219+
if (monitored_resource_for_view == nullptr) {
212220
base_time_series.mutable_resource()->set_type(kDefaultResourceType);
213221
} else {
214-
*base_time_series.mutable_resource() = monitored_resource;
222+
*base_time_series.mutable_resource() = *monitored_resource_for_view;
215223
}
216224
auto* interval = base_time_series.add_points()->mutable_interval();
217225
// Stackdriver doesn't like start_time and end_time being different for GAUGE
@@ -221,9 +229,7 @@ std::vector<google::monitoring::v3::TimeSeries> MakeTimeSeries(
221229
SetTimestamp(data.start_time(), interval->mutable_start_time());
222230
}
223231
SetTimestamp(data.end_time(), interval->mutable_end_time());
224-
if (IsKnownCustomMetric(metric_type)) {
225-
// Custom metrics use this label so that different processes produce
226-
// different timeseries instead of colliding.
232+
if (add_task_label) {
227233
(*base_time_series.mutable_metric()->mutable_labels())[kOpenCensusTaskKey] =
228234
std::string(opencensus_task);
229235
}

opencensus/exporters/stats/stackdriver/internal/stackdriver_utils.h

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,22 +38,29 @@ std::string MakeType(absl::string_view metric_name_prefix,
3838
// custom (i.e not built-in) Stackdriver metric.
3939
bool IsKnownCustomMetric(absl::string_view metric_type);
4040

41+
// Returns a pointer to the MonitoredResource proto for this view, or nullptr if
42+
// the default resource should be used.
43+
const google::api::MonitoredResource* MonitoredResourceForView(
44+
const opencensus::stats::ViewDescriptor& view_descriptor,
45+
const google::api::MonitoredResource& monitored_resource,
46+
const std::unordered_map<std::string, google::api::MonitoredResource>&
47+
per_metric_monitored_resource);
48+
4149
// Populates metric_descriptor. project_name must be in the format
4250
// "projects/project_id". metric_name_prefix must have a trailing slash, e.g.
4351
// "custom.googleapis.com/opencensus/".
4452
void SetMetricDescriptor(
4553
absl::string_view project_name, absl::string_view metric_name_prefix,
4654
const opencensus::stats::ViewDescriptor& view_descriptor,
47-
google::api::MetricDescriptor* metric_descriptor);
55+
bool add_task_label, google::api::MetricDescriptor* metric_descriptor);
4856

49-
// Converts each row of 'data' into TimeSeries.
57+
// Converts each row of 'data' into a TimeSeries proto.
5058
std::vector<google::monitoring::v3::TimeSeries> MakeTimeSeries(
5159
absl::string_view metric_name_prefix,
52-
const google::api::MonitoredResource& monitored_resource,
53-
const std::unordered_map<std::string, google::api::MonitoredResource>&
54-
per_metric_monitored_resource,
60+
const google::api::MonitoredResource* monitored_resource_for_view,
5561
const opencensus::stats::ViewDescriptor& view_descriptor,
56-
const opencensus::stats::ViewData& data, absl::string_view opencensus_task);
62+
const opencensus::stats::ViewData& data, bool add_task_label,
63+
absl::string_view opencensus_task);
5764

5865
// Populates proto based on the given time.
5966
void SetTimestamp(absl::Time time, google::protobuf::Timestamp* proto);

0 commit comments

Comments
 (0)