...

Source file src/go.opencensus.io/stats/record.go

Documentation: go.opencensus.io/stats

     1  // Copyright 2018, OpenCensus Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  
    16  package stats
    17  
    18  import (
    19  	"context"
    20  
    21  	"go.opencensus.io/metric/metricdata"
    22  	"go.opencensus.io/stats/internal"
    23  	"go.opencensus.io/tag"
    24  )
    25  
    26  func init() {
    27  	internal.SubscriptionReporter = func(measure string) {
    28  		mu.Lock()
    29  		measures[measure].subscribe()
    30  		mu.Unlock()
    31  	}
    32  }
    33  
    34  // Recorder provides an interface for exporting measurement information from
    35  // the static Record method by using the WithRecorder option.
    36  type Recorder interface {
    37  	// Record records a set of measurements associated with the given tags and attachments.
    38  	// The second argument is a `[]Measurement`.
    39  	Record(*tag.Map, interface{}, map[string]interface{})
    40  }
    41  
    42  type recordOptions struct {
    43  	attachments  metricdata.Attachments
    44  	mutators     []tag.Mutator
    45  	measurements []Measurement
    46  	recorder     Recorder
    47  }
    48  
    49  // WithAttachments applies provided exemplar attachments.
    50  func WithAttachments(attachments metricdata.Attachments) Options {
    51  	return func(ro *recordOptions) {
    52  		ro.attachments = attachments
    53  	}
    54  }
    55  
    56  // WithTags applies provided tag mutators.
    57  func WithTags(mutators ...tag.Mutator) Options {
    58  	return func(ro *recordOptions) {
    59  		ro.mutators = mutators
    60  	}
    61  }
    62  
    63  // WithMeasurements applies provided measurements.
    64  func WithMeasurements(measurements ...Measurement) Options {
    65  	return func(ro *recordOptions) {
    66  		ro.measurements = measurements
    67  	}
    68  }
    69  
    70  // WithRecorder records the measurements to the specified `Recorder`, rather
    71  // than to the global metrics recorder.
    72  func WithRecorder(meter Recorder) Options {
    73  	return func(ro *recordOptions) {
    74  		ro.recorder = meter
    75  	}
    76  }
    77  
    78  // Options apply changes to recordOptions.
    79  type Options func(*recordOptions)
    80  
    81  func createRecordOption(ros ...Options) *recordOptions {
    82  	o := &recordOptions{}
    83  	for _, ro := range ros {
    84  		ro(o)
    85  	}
    86  	return o
    87  }
    88  
    89  type measurementRecorder = func(tags *tag.Map, measurement []Measurement, attachments map[string]interface{})
    90  
    91  // Record records one or multiple measurements with the same context at once.
    92  // If there are any tags in the context, measurements will be tagged with them.
    93  func Record(ctx context.Context, ms ...Measurement) {
    94  	// Record behaves the same as RecordWithOptions, but because we do not have to handle generic functionality
    95  	// (RecordOptions) we can reduce some allocations to speed up this hot path
    96  	if len(ms) == 0 {
    97  		return
    98  	}
    99  	recorder := internal.MeasurementRecorder.(measurementRecorder)
   100  	record := false
   101  	for _, m := range ms {
   102  		if m.desc.subscribed() {
   103  			record = true
   104  			break
   105  		}
   106  	}
   107  	if !record {
   108  		return
   109  	}
   110  	recorder(tag.FromContext(ctx), ms, nil)
   111  	return
   112  }
   113  
   114  // RecordWithTags records one or multiple measurements at once.
   115  //
   116  // Measurements will be tagged with the tags in the context mutated by the mutators.
   117  // RecordWithTags is useful if you want to record with tag mutations but don't want
   118  // to propagate the mutations in the context.
   119  func RecordWithTags(ctx context.Context, mutators []tag.Mutator, ms ...Measurement) error {
   120  	return RecordWithOptions(ctx, WithTags(mutators...), WithMeasurements(ms...))
   121  }
   122  
   123  // RecordWithOptions records measurements from the given options (if any) against context
   124  // and tags and attachments in the options (if any).
   125  // If there are any tags in the context, measurements will be tagged with them.
   126  func RecordWithOptions(ctx context.Context, ros ...Options) error {
   127  	o := createRecordOption(ros...)
   128  	if len(o.measurements) == 0 {
   129  		return nil
   130  	}
   131  	recorder := internal.DefaultRecorder
   132  	if o.recorder != nil {
   133  		recorder = o.recorder.Record
   134  	}
   135  	if recorder == nil {
   136  		return nil
   137  	}
   138  	record := false
   139  	for _, m := range o.measurements {
   140  		if m.desc.subscribed() {
   141  			record = true
   142  			break
   143  		}
   144  	}
   145  	if !record {
   146  		return nil
   147  	}
   148  	if len(o.mutators) > 0 {
   149  		var err error
   150  		if ctx, err = tag.New(ctx, o.mutators...); err != nil {
   151  			return err
   152  		}
   153  	}
   154  	recorder(tag.FromContext(ctx), o.measurements, o.attachments)
   155  	return nil
   156  }
   157  

View as plain text