/* * Copyright 2017, Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package io.grpc.services; import com.google.common.annotations.VisibleForTesting; import com.google.instrumentation.common.Duration; import com.google.instrumentation.common.Timestamp; import com.google.instrumentation.stats.DistributionAggregation; import com.google.instrumentation.stats.DistributionAggregationDescriptor; import com.google.instrumentation.stats.IntervalAggregation; import com.google.instrumentation.stats.IntervalAggregation.Interval; import com.google.instrumentation.stats.IntervalAggregationDescriptor; import com.google.instrumentation.stats.MeasurementDescriptor; import com.google.instrumentation.stats.MeasurementDescriptor.BasicUnit; import com.google.instrumentation.stats.MeasurementDescriptor.MeasurementUnit; import com.google.instrumentation.stats.Tag; import com.google.instrumentation.stats.TagKey; import com.google.instrumentation.stats.View; import com.google.instrumentation.stats.View.DistributionView; import com.google.instrumentation.stats.View.IntervalView; import com.google.instrumentation.stats.ViewDescriptor; import com.google.instrumentation.stats.ViewDescriptor.DistributionViewDescriptor; import com.google.instrumentation.stats.ViewDescriptor.IntervalViewDescriptor; import com.google.instrumentation.stats.proto.CensusProto; import io.grpc.ExperimentalApi; import io.grpc.instrumentation.v1alpha.StatsResponse; /** Utility methods to support {@link MonitoringService}. */ @ExperimentalApi("https://github.com/grpc/grpc-java/issues/2776") final class MonitoringUtil { private MonitoringUtil() {} /** Serialize a {@link View} and associated descriptors to a {@link StatsResponse}. */ static StatsResponse buildCanonicalRpcStatsView(View view) { return StatsResponse.newBuilder() .setMeasurementDescriptor( serializeMeasurementDescriptor(view.getViewDescriptor().getMeasurementDescriptor())) .setViewDescriptor(serializeViewDescriptor(view.getViewDescriptor())) .setView(serializeView(view)) .build(); } @VisibleForTesting static CensusProto.MeasurementDescriptor serializeMeasurementDescriptor( MeasurementDescriptor measurementDescriptor) { return CensusProto.MeasurementDescriptor.newBuilder() .setName(measurementDescriptor.getName()) .setDescription(measurementDescriptor.getDescription()) .setUnit(serializeMeasurementUnit(measurementDescriptor.getUnit())) .build(); } @VisibleForTesting static CensusProto.MeasurementDescriptor.MeasurementUnit serializeMeasurementUnit( MeasurementUnit unit) { CensusProto.MeasurementDescriptor.MeasurementUnit.Builder unitBuilder = CensusProto.MeasurementDescriptor.MeasurementUnit.newBuilder() .setPower10(unit.getPower10()); for (BasicUnit basicUnit : unit.getNumerators()) { unitBuilder.addNumerators(serializeBasicUnit(basicUnit)); } for (BasicUnit basicUnit : unit.getDenominators()) { unitBuilder.addDenominators(serializeBasicUnit(basicUnit)); } return unitBuilder.build(); } @VisibleForTesting static CensusProto.MeasurementDescriptor.BasicUnit serializeBasicUnit(BasicUnit basicUnit) { switch (basicUnit) { case SCALAR: return CensusProto.MeasurementDescriptor.BasicUnit.SCALAR; case BITS: return CensusProto.MeasurementDescriptor.BasicUnit.BITS; case BYTES: return CensusProto.MeasurementDescriptor.BasicUnit.BYTES; case SECONDS: return CensusProto.MeasurementDescriptor.BasicUnit.SECONDS; case CORES: return CensusProto.MeasurementDescriptor.BasicUnit.CORES; default: return CensusProto.MeasurementDescriptor.BasicUnit.UNKNOWN; } } @VisibleForTesting static CensusProto.ViewDescriptor serializeViewDescriptor(ViewDescriptor viewDescriptor) { CensusProto.ViewDescriptor.Builder viewDescriptorBuilder = CensusProto.ViewDescriptor.newBuilder() .setName(viewDescriptor.getName()) .setDescription(viewDescriptor.getDescription()) .setMeasurementDescriptorName(viewDescriptor.getMeasurementDescriptor().getName()); for (TagKey tagKey : viewDescriptor.getTagKeys()) { viewDescriptorBuilder.addTagKeys(tagKey.toString()); } if (viewDescriptor instanceof DistributionViewDescriptor) { viewDescriptorBuilder.setDistributionAggregation( serializeDistributionAggregationDescriptor( ((DistributionViewDescriptor) viewDescriptor) .getDistributionAggregationDescriptor())); } else { viewDescriptorBuilder.setIntervalAggregation( serializeIntervalAggregationDescriptor( ((IntervalViewDescriptor) viewDescriptor).getIntervalAggregationDescriptor())); } return viewDescriptorBuilder.build(); } @VisibleForTesting static CensusProto.DistributionAggregationDescriptor serializeDistributionAggregationDescriptor( DistributionAggregationDescriptor distributionAggregationDescriptor) { CensusProto.DistributionAggregationDescriptor.Builder distributionAggregationDescriptorBuilder = CensusProto.DistributionAggregationDescriptor.newBuilder(); if (distributionAggregationDescriptor.getBucketBoundaries() != null) { distributionAggregationDescriptorBuilder.addAllBucketBounds( distributionAggregationDescriptor.getBucketBoundaries()); } return distributionAggregationDescriptorBuilder.build(); } @VisibleForTesting static CensusProto.IntervalAggregationDescriptor serializeIntervalAggregationDescriptor( IntervalAggregationDescriptor intervalAggregationDescriptor) { CensusProto.IntervalAggregationDescriptor.Builder intervalAggregationDescriptorBuilder = CensusProto.IntervalAggregationDescriptor.newBuilder() .setNSubIntervals(intervalAggregationDescriptor.getNumSubIntervals()); for (Duration intervalSize : intervalAggregationDescriptor.getIntervalSizes()) { intervalAggregationDescriptorBuilder.addIntervalSizes(serializeDuration(intervalSize)); } return intervalAggregationDescriptorBuilder.build(); } @VisibleForTesting static CensusProto.Duration serializeDuration(Duration duration) { return CensusProto.Duration.newBuilder() .setSeconds(duration.getSeconds()) .setNanos(duration.getNanos()) .build(); } @VisibleForTesting static CensusProto.View serializeView(View view) { CensusProto.View.Builder viewBuilder = CensusProto.View.newBuilder().setViewName(view.getViewDescriptor().getName()); if (view instanceof DistributionView) { viewBuilder.setDistributionView(serializeDistributionView((DistributionView) view)); } else { viewBuilder.setIntervalView(serializeIntervalView((IntervalView) view)); } return viewBuilder.build(); } @VisibleForTesting static CensusProto.DistributionView serializeDistributionView(DistributionView distributionView) { CensusProto.DistributionView.Builder distributionViewBuilder = CensusProto.DistributionView.newBuilder(); //TODO(ericgribkoff) Re-enable once getter methods are public in instrumentation. //distributionViewBuilder.setStart(serializeTimestamp(distributionView.getStart())) //distributionViewBuilder.setEnd(serializeTimestamp(distributionView.getEnd())); for (DistributionAggregation aggregation : distributionView.getDistributionAggregations()) { distributionViewBuilder.addAggregations(serializeDistributionAggregation(aggregation)); } return distributionViewBuilder.build(); } @VisibleForTesting static CensusProto.Timestamp serializeTimestamp(Timestamp timestamp) { return CensusProto.Timestamp.newBuilder() .setSeconds(timestamp.getSeconds()) .setNanos(timestamp.getNanos()) .build(); } @VisibleForTesting static CensusProto.DistributionAggregation serializeDistributionAggregation( DistributionAggregation aggregation) { CensusProto.DistributionAggregation.Builder aggregationBuilder = CensusProto.DistributionAggregation.newBuilder() .setCount(aggregation.getCount()) .setMean(aggregation.getMean()) .setSum(aggregation.getSum()) .setRange(serializeRange(aggregation.getRange())); if (aggregation.getBucketCounts() != null) { aggregationBuilder.addAllBucketCounts(aggregation.getBucketCounts()); } for (Tag tag : aggregation.getTags()) { aggregationBuilder.addTags(serializeTag(tag)); } return aggregationBuilder.build(); } @VisibleForTesting static CensusProto.DistributionAggregation.Range serializeRange( DistributionAggregation.Range range) { CensusProto.DistributionAggregation.Range.Builder builder = CensusProto.DistributionAggregation.Range.newBuilder(); if (range != null) { builder.setMin(range.getMin()).setMax(range.getMax()); } return builder.build(); } @VisibleForTesting static CensusProto.Tag serializeTag(Tag tag) { return CensusProto.Tag.newBuilder() .setKey(tag.getKey().toString()) .setValue(tag.getValue().toString()) .build(); } @VisibleForTesting static CensusProto.IntervalView serializeIntervalView(IntervalView intervalView) { CensusProto.IntervalView.Builder intervalViewBuilder = CensusProto.IntervalView.newBuilder(); for (IntervalAggregation aggregation : intervalView.getIntervalAggregations()) { intervalViewBuilder.addAggregations(serializeIntervalAggregation(aggregation)); } return intervalViewBuilder.build(); } @VisibleForTesting static CensusProto.IntervalAggregation serializeIntervalAggregation( IntervalAggregation aggregation) { CensusProto.IntervalAggregation.Builder aggregationBuilder = CensusProto.IntervalAggregation.newBuilder(); for (Interval interval : aggregation.getIntervals()) { aggregationBuilder.addIntervals(serializeInterval(interval)); } for (Tag tag : aggregation.getTags()) { aggregationBuilder.addTags(serializeTag(tag)); } return aggregationBuilder.build(); } @VisibleForTesting static CensusProto.IntervalAggregation.Interval serializeInterval(Interval interval) { return CensusProto.IntervalAggregation.Interval.newBuilder() .setIntervalSize(serializeDuration(interval.getIntervalSize())) .setCount(interval.getCount()) .setSum(interval.getSum()) .build(); } }