@@ -103,7 +103,8 @@ static List<TimeSeries> convertToSpannerTimeSeries(
103103 metricData .getData ().getPoints ().stream ()
104104 .map (
105105 pointData ->
106- convertPointToSpannerTimeSeries (metricData , pointData , monitoredResourceBuilder ))
106+ convertPointToSpannerTimeSeries (
107+ metricData , pointData , monitoredResourceBuilder , projectId ))
107108 .forEach (allTimeSeries ::add );
108109 }
109110 return allTimeSeries ;
@@ -112,7 +113,8 @@ static List<TimeSeries> convertToSpannerTimeSeries(
112113 private static TimeSeries convertPointToSpannerTimeSeries (
113114 MetricData metricData ,
114115 PointData pointData ,
115- MonitoredResource .Builder monitoredResourceBuilder ) {
116+ MonitoredResource .Builder monitoredResourceBuilder ,
117+ String projectId ) {
116118 TimeSeries .Builder builder =
117119 TimeSeries .newBuilder ()
118120 .setMetricKind (convertMetricKind (metricData ))
@@ -208,7 +210,8 @@ private static Point createPoint(
208210 return builder
209211 .setValue (
210212 TypedValue .newBuilder ()
211- .setDistributionValue (convertHistogramData ((HistogramPointData ) pointData ))
213+ .setDistributionValue (
214+ convertHistogramData ((HistogramPointData ) pointData , projectId ))
212215 .build ())
213216 .build ();
214217 case DOUBLE_GAUGE :
@@ -238,6 +241,49 @@ private static Distribution convertHistogramData(HistogramPointData pointData, S
238241 BucketOptions .newBuilder ()
239242 .setExplicitBuckets (Explicit .newBuilder ().addAllBounds (pointData .getBoundaries ())))
240243 .addAllBucketCounts (pointData .getCounts ())
244+ .addAllExemplars (
245+ pointData .getExemplars ().stream ()
246+ .map (e -> mapExemplar (e , projectId ))
247+ .collect (Collectors .toList ()))
248+ .build ();
249+ }
250+
251+ private static Distribution .Exemplar mapExemplar (ExemplarData exemplar , String projectId ) {
252+ double value = 0 ;
253+ if (exemplar instanceof DoubleExemplarData ) {
254+ value = ((DoubleExemplarData ) exemplar ).getValue ();
255+ } else if (exemplar instanceof LongExemplarData ) {
256+ value = ((LongExemplarData ) exemplar ).getValue ();
257+ }
258+
259+ Distribution .Exemplar .Builder exemplarBuilder =
260+ Distribution .Exemplar .newBuilder ()
261+ .setValue (value )
262+ .setTimestamp (mapTimestamp (exemplar .getEpochNanos ()));
263+ if (exemplar .getSpanContext ().isValid ()) {
264+ exemplarBuilder .addAttachments (
265+ Any .pack (
266+ SpanContext .newBuilder ()
267+ .setSpanName (
268+ makeSpanName (
269+ projectId ,
270+ exemplar .getSpanContext ().getTraceId (),
271+ exemplar .getSpanContext ().getSpanId ()))
272+ .build ()));
273+ }
274+ if (!exemplar .getFilteredAttributes ().isEmpty ()) {
275+ exemplarBuilder .addAttachments (
276+ Any .pack (mapFilteredAttributes (exemplar .getFilteredAttributes ())));
277+ }
278+ return exemplarBuilder .build ();
279+ }
280+
281+ static final long NANO_PER_SECOND = (long ) 1e9 ;
282+
283+ private static Timestamp mapTimestamp (long epochNanos ) {
284+ return Timestamp .newBuilder ()
285+ .setSeconds (epochNanos / NANO_PER_SECOND )
286+ .setNanos ((int ) (epochNanos % NANO_PER_SECOND ))
241287 .build ();
242288 }
243289
0 commit comments