fix: always add instance-id for built-in metrics (#3612) · googleapis/java-spanner@705b627 (original) (raw)

`@@ -39,6 +39,7 @@

`

39

39

`import io.opentelemetry.sdk.metrics.InstrumentType;

`

40

40

`import io.opentelemetry.sdk.metrics.data.AggregationTemporality;

`

41

41

`import io.opentelemetry.sdk.metrics.data.MetricData;

`

``

42

`+

import io.opentelemetry.sdk.metrics.data.PointData;

`

42

43

`import io.opentelemetry.sdk.metrics.export.MetricExporter;

`

43

44

`import java.io.IOException;

`

44

45

`import java.time.Duration;

`

`@@ -49,6 +50,7 @@

`

49

50

`import java.util.logging.Level;

`

50

51

`import java.util.logging.Logger;

`

51

52

`import java.util.stream.Collectors;

`

``

53

`+

import javax.annotation.Nonnull;

`

52

54

`import javax.annotation.Nullable;

`

53

55

``

54

56

`/**

`

`@@ -66,7 +68,7 @@ class SpannerCloudMonitoringExporter implements MetricExporter {

`

66

68

`// https://cloud.google.com/monitoring/quotas#custom_metrics_quotas.

`

67

69

`private static final int EXPORT_BATCH_SIZE_LIMIT = 200;

`

68

70

`private final AtomicBoolean spannerExportFailureLogged = new AtomicBoolean(false);

`

69

``

`-

private CompletableResultCode lastExportCode;

`

``

71

`+

private final AtomicBoolean lastExportSkippedData = new AtomicBoolean(false);

`

70

72

`private final MetricServiceClient client;

`

71

73

`private final String spannerProjectId;

`

72

74

``

`@@ -101,44 +103,49 @@ static SpannerCloudMonitoringExporter create(

`

101

103

` }

`

102

104

``

103

105

`@Override

`

104

``

`-

public CompletableResultCode export(Collection collection) {

`

``

106

`+

public CompletableResultCode export(@Nonnull Collection collection) {

`

105

107

`if (client.isShutdown()) {

`

106

108

`logger.log(Level.WARNING, "Exporter is shut down");

`

107

109

`return CompletableResultCode.ofFailure();

`

108

110

` }

`

109

111

``

110

``

`-

this.lastExportCode = exportSpannerClientMetrics(collection);

`

111

``

`-

return lastExportCode;

`

``

112

`+

return exportSpannerClientMetrics(collection);

`

112

113

` }

`

113

114

``

114

115

`/** Export client built in metrics */

`

115

116

`private CompletableResultCode exportSpannerClientMetrics(Collection collection) {

`

116

``

`-

// Filter spanner metrics

`

``

117

`+

// Filter spanner metrics. Only include metrics that contain a project and instance ID.

`

117

118

`List spannerMetricData =

`

118

119

`collection.stream()

`

119

120

` .filter(md -> SPANNER_METRICS.contains(md.getName()))

`

120

121

` .collect(Collectors.toList());

`

121

122

``

122

``

`-

// Skips exporting if there's none

`

123

``

`-

if (spannerMetricData.isEmpty()) {

`

124

``

`-

return CompletableResultCode.ofSuccess();

`

125

``

`-

}

`

126

``

-

127

``

`-

// Verifies metrics project id is the same as the spanner project id set on this client

`

128

``

`-

if (!spannerMetricData.stream()

`

``

123

`+

// Log warnings for metrics that will be skipped.

`

``

124

`+

boolean mustFilter = false;

`

``

125

`+

if (spannerMetricData.stream()

`

129

126

` .flatMap(metricData -> metricData.getData().getPoints().stream())

`

130

``

`-

.allMatch(

`

131

``

`-

pd -> spannerProjectId.equals(SpannerCloudMonitoringExporterUtils.getProjectId(pd)))) {

`

132

``

`-

logger.log(Level.WARNING, "Metric data has a different projectId. Skipping export.");

`

133

``

`-

return CompletableResultCode.ofFailure();

`

``

127

`+

.anyMatch(this::shouldSkipPointDataDueToProjectId)) {

`

``

128

`+

logger.log(

`

``

129

`+

Level.WARNING, "Some metric data contain a different projectId. These will be skipped.");

`

``

130

`+

mustFilter = true;

`

134

131

` }

`

135

``

-

136

``

`-

// Verifies if metrics data has missing instance id.

`

137

132

`if (spannerMetricData.stream()

`

138

133

` .flatMap(metricData -> metricData.getData().getPoints().stream())

`

139

``

`-

.anyMatch(pd -> SpannerCloudMonitoringExporterUtils.getInstanceId(pd) == null)) {

`

140

``

`-

logger.log(Level.WARNING, "Metric data has missing instanceId. Skipping export.");

`

141

``

`-

return CompletableResultCode.ofFailure();

`

``

134

`+

.anyMatch(this::shouldSkipPointDataDueToMissingInstanceId)) {

`

``

135

`+

logger.log(Level.WARNING, "Some metric data miss instanceId. These will be skipped.");

`

``

136

`+

mustFilter = true;

`

``

137

`+

}

`

``

138

`+

if (mustFilter) {

`

``

139

`+

spannerMetricData =

`

``

140

`+

spannerMetricData.stream()

`

``

141

`+

.filter(this::shouldSkipMetricData)

`

``

142

`+

.collect(Collectors.toList());

`

``

143

`+

}

`

``

144

`+

lastExportSkippedData.set(mustFilter);

`

``

145

+

``

146

`+

// Skips exporting if there's none

`

``

147

`+

if (spannerMetricData.isEmpty()) {

`

``

148

`+

return CompletableResultCode.ofSuccess();

`

142

149

` }

`

143

150

``

144

151

`List spannerTimeSeries;

`

`@@ -190,6 +197,26 @@ public void onSuccess(List empty) {

`

190

197

`return spannerExportCode;

`

191

198

` }

`

192

199

``

``

200

`+

private boolean shouldSkipMetricData(MetricData metricData) {

`

``

201

`+

return metricData.getData().getPoints().stream()

`

``

202

`+

.anyMatch(

`

``

203

`+

pd ->

`

``

204

`+

shouldSkipPointDataDueToProjectId(pd)

`

``

205

`+

|| shouldSkipPointDataDueToMissingInstanceId(pd));

`

``

206

`+

}

`

``

207

+

``

208

`+

private boolean shouldSkipPointDataDueToProjectId(PointData pointData) {

`

``

209

`+

return !spannerProjectId.equals(SpannerCloudMonitoringExporterUtils.getProjectId(pointData));

`

``

210

`+

}

`

``

211

+

``

212

`+

private boolean shouldSkipPointDataDueToMissingInstanceId(PointData pointData) {

`

``

213

`+

return SpannerCloudMonitoringExporterUtils.getInstanceId(pointData) == null;

`

``

214

`+

}

`

``

215

+

``

216

`+

boolean lastExportSkippedData() {

`

``

217

`+

return this.lastExportSkippedData.get();

`

``

218

`+

}

`

``

219

+

193

220

`private ApiFuture<List> exportTimeSeriesInBatch(

`

194

221

`ProjectName projectName, List timeSeries) {

`

195

222

`List<ApiFuture> batchResults = new ArrayList<>();

`

`@@ -233,7 +260,7 @@ public CompletableResultCode shutdown() {

`

233

260

` * metric over time.

`

234

261

` */

`

235

262

`@Override

`

236

``

`-

public AggregationTemporality getAggregationTemporality(InstrumentType instrumentType) {

`

``

263

`+

public AggregationTemporality getAggregationTemporality(@Nonnull InstrumentType instrumentType) {

`

237

264

`return AggregationTemporality.CUMULATIVE;

`

238

265

` }

`

239

266

`}

`