| 
									
										
										
										
											2020-03-23 22:41:10 -07:00
										 |  |  | // Copyright The OpenTelemetry Authors | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | // | 
					
						
							|  |  |  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  | // you may not use this file except in compliance with the License. | 
					
						
							|  |  |  | // You may obtain a copy of the License at | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | //     http://www.apache.org/licenses/LICENSE-2.0 | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  | // distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  | // See the License for the specific language governing permissions and | 
					
						
							|  |  |  | // limitations under the License. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-04 18:10:58 +01:00
										 |  |  | package metric // import "go.opentelemetry.io/otel/sdk/metric" | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2019-11-15 13:01:20 -08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2020-02-10 16:20:29 -08:00
										 |  |  | 	"runtime" | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | 	"sync" | 
					
						
							|  |  |  | 	"sync/atomic" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-16 18:30:54 +01:00
										 |  |  | 	"go.opentelemetry.io/otel" | 
					
						
							| 
									
										
										
										
											2021-02-18 12:59:37 -05:00
										 |  |  | 	"go.opentelemetry.io/otel/attribute" | 
					
						
							| 
									
										
										
										
											2020-10-11 11:46:29 -07:00
										 |  |  | 	internal "go.opentelemetry.io/otel/internal/metric" | 
					
						
							| 
									
										
										
										
											2020-11-12 16:28:32 +01:00
										 |  |  | 	"go.opentelemetry.io/otel/metric" | 
					
						
							| 
									
										
										
										
											2020-11-11 16:24:12 +01:00
										 |  |  | 	"go.opentelemetry.io/otel/metric/number" | 
					
						
							| 
									
										
										
										
											2019-11-05 13:08:55 -08:00
										 |  |  | 	export "go.opentelemetry.io/otel/sdk/export/metric" | 
					
						
							| 
									
										
										
										
											2020-06-09 22:53:30 -07:00
										 |  |  | 	"go.opentelemetry.io/otel/sdk/metric/aggregator" | 
					
						
							| 
									
										
										
										
											2020-05-18 17:44:28 -07:00
										 |  |  | 	"go.opentelemetry.io/otel/sdk/resource" | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type ( | 
					
						
							| 
									
										
										
										
											2020-05-11 10:23:06 -07:00
										 |  |  | 	// Accumulator implements the OpenTelemetry Meter API.  The | 
					
						
							| 
									
										
										
										
											2020-06-23 12:00:15 -07:00
										 |  |  | 	// Accumulator is bound to a single export.Processor in | 
					
						
							| 
									
										
										
										
											2020-05-11 10:23:06 -07:00
										 |  |  | 	// `NewAccumulator()`. | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | 	// | 
					
						
							| 
									
										
										
										
											2020-05-11 10:23:06 -07:00
										 |  |  | 	// The Accumulator supports a Collect() API to gather and export | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | 	// current data.  Collect() should be arranged according to | 
					
						
							| 
									
										
										
										
											2020-06-23 12:00:15 -07:00
										 |  |  | 	// the processor model.  Push-based processors will setup a | 
					
						
							|  |  |  | 	// timer to call Collect() periodically.  Pull-based processors | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | 	// will call Collect() when a pull request arrives. | 
					
						
							| 
									
										
										
										
											2020-05-11 10:23:06 -07:00
										 |  |  | 	Accumulator struct { | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | 		// current maps `mapkey` to *record. | 
					
						
							|  |  |  | 		current sync.Map | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-19 12:02:46 -07:00
										 |  |  | 		// asyncInstruments is a set of | 
					
						
							|  |  |  | 		// `*asyncInstrument` instances | 
					
						
							| 
									
										
										
										
											2020-05-13 16:27:52 -07:00
										 |  |  | 		asyncLock        sync.Mutex | 
					
						
							|  |  |  | 		asyncInstruments *internal.AsyncInstrumentState | 
					
						
							| 
									
										
										
										
											2020-03-05 12:15:30 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | 		// currentEpoch is the current epoch number. It is | 
					
						
							|  |  |  | 		// incremented in `Collect()`. | 
					
						
							|  |  |  | 		currentEpoch int64 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-23 12:00:15 -07:00
										 |  |  | 		// processor is the configured processor+configuration. | 
					
						
							|  |  |  | 		processor export.Processor | 
					
						
							| 
									
										
										
										
											2019-11-15 13:01:20 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | 		// collectLock prevents simultaneous calls to Collect(). | 
					
						
							|  |  |  | 		collectLock sync.Mutex | 
					
						
							| 
									
										
										
										
											2019-11-15 13:01:20 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-27 14:06:48 -07:00
										 |  |  | 		// asyncSortSlice has a single purpose - as a temporary | 
					
						
							|  |  |  | 		// place for sorting during labels creation to avoid | 
					
						
							|  |  |  | 		// allocation.  It is cleared after use. | 
					
						
							| 
									
										
										
										
											2021-02-18 12:59:37 -05:00
										 |  |  | 		asyncSortSlice attribute.Sortable | 
					
						
							| 
									
										
										
										
											2020-05-18 17:44:28 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// resource is applied to all records in this Accumulator. | 
					
						
							|  |  |  | 		resource *resource.Resource | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-19 12:02:46 -07:00
										 |  |  | 	syncInstrument struct { | 
					
						
							|  |  |  | 		instrument | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// mapkey uniquely describes a metric instrument in terms of | 
					
						
							| 
									
										
										
										
											2020-03-27 14:06:48 -07:00
										 |  |  | 	// its InstrumentID and the encoded form of its labels. | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | 	mapkey struct { | 
					
						
							| 
									
										
										
										
											2020-11-12 16:28:32 +01:00
										 |  |  | 		descriptor *metric.Descriptor | 
					
						
							| 
									
										
										
										
											2021-02-18 12:59:37 -05:00
										 |  |  | 		ordered    attribute.Distinct | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// record maintains the state of one metric instrument.  Due | 
					
						
							|  |  |  | 	// the use of lock-free algorithms, there may be more than one | 
					
						
							|  |  |  | 	// `record` in existence at a time, although at most one can | 
					
						
							| 
									
										
										
										
											2020-05-11 10:23:06 -07:00
										 |  |  | 	// be referenced from the `Accumulator.current` map. | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | 	record struct { | 
					
						
							| 
									
										
										
										
											2020-02-06 14:45:56 -08:00
										 |  |  | 		// refMapped keeps track of refcounts and the mapping state to the | 
					
						
							| 
									
										
										
										
											2020-05-11 10:23:06 -07:00
										 |  |  | 		// Accumulator.current map. | 
					
						
							| 
									
										
										
										
											2020-02-06 14:45:56 -08:00
										 |  |  | 		refMapped refcountMapped | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-21 20:23:15 -07:00
										 |  |  | 		// updateCount is incremented on every Update. | 
					
						
							|  |  |  | 		updateCount int64 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// collectedCount is set to updateCount on collection, | 
					
						
							|  |  |  | 		// supports checking for no updates during a round. | 
					
						
							|  |  |  | 		collectedCount int64 | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-23 12:10:58 -07:00
										 |  |  | 		// storage is the stored label set for this record, | 
					
						
							|  |  |  | 		// except in cases where a label set is shared due to | 
					
						
							|  |  |  | 		// batch recording. | 
					
						
							| 
									
										
										
										
											2021-02-18 12:59:37 -05:00
										 |  |  | 		storage attribute.Set | 
					
						
							| 
									
										
										
										
											2020-04-23 12:10:58 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-27 14:06:48 -07:00
										 |  |  | 		// labels is the processed label set for this record. | 
					
						
							| 
									
										
										
										
											2020-04-23 12:10:58 -07:00
										 |  |  | 		// this may refer to the `storage` field in another | 
					
						
							|  |  |  | 		// record if this label set is shared resulting from | 
					
						
							|  |  |  | 		// `RecordBatch`. | 
					
						
							| 
									
										
										
										
											2021-02-18 12:59:37 -05:00
										 |  |  | 		labels *attribute.Set | 
					
						
							| 
									
										
										
										
											2020-03-27 14:06:48 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// sortSlice has a single purpose - as a temporary | 
					
						
							|  |  |  | 		// place for sorting during labels creation to avoid | 
					
						
							|  |  |  | 		// allocation. | 
					
						
							| 
									
										
										
										
											2021-02-18 12:59:37 -05:00
										 |  |  | 		sortSlice attribute.Sortable | 
					
						
							| 
									
										
										
										
											2020-01-06 10:08:40 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-19 12:02:46 -07:00
										 |  |  | 		// inst is a pointer to the corresponding instrument. | 
					
						
							|  |  |  | 		inst *syncInstrument | 
					
						
							| 
									
										
										
										
											2020-01-06 10:08:40 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-13 00:55:01 -07:00
										 |  |  | 		// current implements the actual RecordOne() API, | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | 		// depending on the type of aggregation.  If nil, the | 
					
						
							|  |  |  | 		// metric was disabled by the exporter. | 
					
						
							| 
									
										
										
										
											2020-06-13 00:55:01 -07:00
										 |  |  | 		current    export.Aggregator | 
					
						
							|  |  |  | 		checkpoint export.Aggregator | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-19 12:02:46 -07:00
										 |  |  | 	instrument struct { | 
					
						
							| 
									
										
										
										
											2020-05-11 10:23:06 -07:00
										 |  |  | 		meter      *Accumulator | 
					
						
							| 
									
										
										
										
											2020-11-12 16:28:32 +01:00
										 |  |  | 		descriptor metric.Descriptor | 
					
						
							| 
									
										
										
										
											2020-03-05 12:15:30 -08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-19 12:02:46 -07:00
										 |  |  | 	asyncInstrument struct { | 
					
						
							|  |  |  | 		instrument | 
					
						
							| 
									
										
										
										
											2020-03-11 09:11:27 -07:00
										 |  |  | 		// recorders maps ordered labels to the pair of | 
					
						
							| 
									
										
										
										
											2020-03-05 12:15:30 -08:00
										 |  |  | 		// labelset and recorder | 
					
						
							| 
									
										
										
										
											2021-02-18 12:59:37 -05:00
										 |  |  | 		recorders map[attribute.Distinct]*labeledRecorder | 
					
						
							| 
									
										
										
										
											2020-03-05 12:15:30 -08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	labeledRecorder struct { | 
					
						
							| 
									
										
										
										
											2020-04-21 20:23:15 -07:00
										 |  |  | 		observedEpoch int64 | 
					
						
							| 
									
										
										
										
											2021-02-18 12:59:37 -05:00
										 |  |  | 		labels        *attribute.Set | 
					
						
							| 
									
										
										
										
											2020-06-13 00:55:01 -07:00
										 |  |  | 		observed      export.Aggregator | 
					
						
							| 
									
										
										
										
											2020-03-05 12:15:30 -08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var ( | 
					
						
							| 
									
										
										
										
											2020-11-12 16:28:32 +01:00
										 |  |  | 	_ metric.MeterImpl     = &Accumulator{} | 
					
						
							|  |  |  | 	_ metric.AsyncImpl     = &asyncInstrument{} | 
					
						
							|  |  |  | 	_ metric.SyncImpl      = &syncInstrument{} | 
					
						
							|  |  |  | 	_ metric.BoundSyncImpl = &record{} | 
					
						
							| 
									
										
										
										
											2020-05-20 10:19:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-08 19:10:01 +02:00
										 |  |  | 	// ErrUninitializedInstrument is returned when an instrument is used when uninitialized. | 
					
						
							| 
									
										
										
										
											2020-05-20 10:19:51 -07:00
										 |  |  | 	ErrUninitializedInstrument = fmt.Errorf("use of an uninitialized instrument") | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-12 16:28:32 +01:00
										 |  |  | func (inst *instrument) Descriptor() metric.Descriptor { | 
					
						
							| 
									
										
										
										
											2020-03-19 12:02:46 -07:00
										 |  |  | 	return inst.descriptor | 
					
						
							| 
									
										
										
										
											2020-03-05 12:15:30 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-19 12:02:46 -07:00
										 |  |  | func (a *asyncInstrument) Implementation() interface{} { | 
					
						
							|  |  |  | 	return a | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *syncInstrument) Implementation() interface{} { | 
					
						
							|  |  |  | 	return s | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-18 12:59:37 -05:00
										 |  |  | func (a *asyncInstrument) observe(num number.Number, labels *attribute.Set) { | 
					
						
							| 
									
										
										
										
											2020-11-11 16:24:12 +01:00
										 |  |  | 	if err := aggregator.RangeTest(num, &a.descriptor); err != nil { | 
					
						
							| 
									
										
										
										
											2020-11-16 18:30:54 +01:00
										 |  |  | 		otel.Handle(err) | 
					
						
							| 
									
										
										
										
											2020-03-05 12:15:30 -08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-03-27 14:06:48 -07:00
										 |  |  | 	recorder := a.getRecorder(labels) | 
					
						
							| 
									
										
										
										
											2020-03-05 12:15:30 -08:00
										 |  |  | 	if recorder == nil { | 
					
						
							|  |  |  | 		// The instrument is disabled according to the | 
					
						
							| 
									
										
										
										
											2020-06-23 10:51:15 -07:00
										 |  |  | 		// AggregatorSelector. | 
					
						
							| 
									
										
										
										
											2020-03-05 12:15:30 -08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-11-11 16:24:12 +01:00
										 |  |  | 	if err := recorder.Update(context.Background(), num, &a.descriptor); err != nil { | 
					
						
							| 
									
										
										
										
											2020-11-16 18:30:54 +01:00
										 |  |  | 		otel.Handle(err) | 
					
						
							| 
									
										
										
										
											2020-03-05 12:15:30 -08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-18 12:59:37 -05:00
										 |  |  | func (a *asyncInstrument) getRecorder(labels *attribute.Set) export.Aggregator { | 
					
						
							| 
									
										
										
										
											2020-04-23 12:10:58 -07:00
										 |  |  | 	lrec, ok := a.recorders[labels.Equivalent()] | 
					
						
							| 
									
										
										
										
											2020-03-05 12:15:30 -08:00
										 |  |  | 	if ok { | 
					
						
							| 
									
										
										
										
											2020-12-10 18:13:08 -08:00
										 |  |  | 		// Note: SynchronizedMove(nil) can't return an error | 
					
						
							|  |  |  | 		_ = lrec.observed.SynchronizedMove(nil, &a.descriptor) | 
					
						
							|  |  |  | 		lrec.observedEpoch = a.meter.currentEpoch | 
					
						
							| 
									
										
										
										
											2020-04-23 12:10:58 -07:00
										 |  |  | 		a.recorders[labels.Equivalent()] = lrec | 
					
						
							| 
									
										
										
										
											2020-06-13 00:55:01 -07:00
										 |  |  | 		return lrec.observed | 
					
						
							| 
									
										
										
										
											2020-03-05 12:15:30 -08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-06-13 00:55:01 -07:00
										 |  |  | 	var rec export.Aggregator | 
					
						
							| 
									
										
										
										
											2020-06-23 12:00:15 -07:00
										 |  |  | 	a.meter.processor.AggregatorFor(&a.descriptor, &rec) | 
					
						
							| 
									
										
										
										
											2020-03-19 12:02:46 -07:00
										 |  |  | 	if a.recorders == nil { | 
					
						
							| 
									
										
										
										
											2021-02-18 12:59:37 -05:00
										 |  |  | 		a.recorders = make(map[attribute.Distinct]*labeledRecorder) | 
					
						
							| 
									
										
										
										
											2020-03-05 12:15:30 -08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	// This may store nil recorder in the map, thus disabling the | 
					
						
							| 
									
										
										
										
											2020-03-19 12:02:46 -07:00
										 |  |  | 	// asyncInstrument for the labelset for good. This is intentional, | 
					
						
							| 
									
										
										
										
											2020-03-05 12:15:30 -08:00
										 |  |  | 	// but will be revisited later. | 
					
						
							| 
									
										
										
										
											2020-04-23 12:10:58 -07:00
										 |  |  | 	a.recorders[labels.Equivalent()] = &labeledRecorder{ | 
					
						
							| 
									
										
										
										
											2020-06-13 00:55:01 -07:00
										 |  |  | 		observed:      rec, | 
					
						
							| 
									
										
										
										
											2020-05-13 16:27:52 -07:00
										 |  |  | 		labels:        labels, | 
					
						
							| 
									
										
										
										
											2020-04-21 20:23:15 -07:00
										 |  |  | 		observedEpoch: a.meter.currentEpoch, | 
					
						
							| 
									
										
										
										
											2020-03-05 12:15:30 -08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return rec | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-27 14:06:48 -07:00
										 |  |  | // acquireHandle gets or creates a `*record` corresponding to `kvs`, | 
					
						
							|  |  |  | // the input labels.  The second argument `labels` is passed in to | 
					
						
							|  |  |  | // support re-use of the orderedLabels computed by a previous | 
					
						
							|  |  |  | // measurement in the same batch.   This performs two allocations | 
					
						
							|  |  |  | // in the common case. | 
					
						
							| 
									
										
										
										
											2021-02-18 12:59:37 -05:00
										 |  |  | func (s *syncInstrument) acquireHandle(kvs []attribute.KeyValue, labelPtr *attribute.Set) *record { | 
					
						
							| 
									
										
										
										
											2020-03-27 14:06:48 -07:00
										 |  |  | 	var rec *record | 
					
						
							| 
									
										
										
										
											2021-02-18 12:59:37 -05:00
										 |  |  | 	var equiv attribute.Distinct | 
					
						
							| 
									
										
										
										
											2020-03-27 14:06:48 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-23 12:10:58 -07:00
										 |  |  | 	if labelPtr == nil { | 
					
						
							| 
									
										
										
										
											2020-03-27 14:06:48 -07:00
										 |  |  | 		// This memory allocation may not be used, but it's | 
					
						
							|  |  |  | 		// needed for the `sortSlice` field, to avoid an | 
					
						
							|  |  |  | 		// allocation while sorting. | 
					
						
							|  |  |  | 		rec = &record{} | 
					
						
							| 
									
										
										
										
											2021-02-18 12:59:37 -05:00
										 |  |  | 		rec.storage = attribute.NewSetWithSortable(kvs, &rec.sortSlice) | 
					
						
							| 
									
										
										
										
											2020-04-23 12:10:58 -07:00
										 |  |  | 		rec.labels = &rec.storage | 
					
						
							|  |  |  | 		equiv = rec.storage.Equivalent() | 
					
						
							| 
									
										
										
										
											2020-03-27 14:06:48 -07:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2020-04-23 12:10:58 -07:00
										 |  |  | 		equiv = labelPtr.Equivalent() | 
					
						
							| 
									
										
										
										
											2020-03-27 14:06:48 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Create lookup key for sync.Map (one allocation, as this | 
					
						
							|  |  |  | 	// passes through an interface{}) | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | 	mk := mapkey{ | 
					
						
							| 
									
										
										
										
											2020-03-19 12:02:46 -07:00
										 |  |  | 		descriptor: &s.descriptor, | 
					
						
							| 
									
										
										
										
											2020-04-23 12:10:58 -07:00
										 |  |  | 		ordered:    equiv, | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-19 12:02:46 -07:00
										 |  |  | 	if actual, ok := s.meter.current.Load(mk); ok { | 
					
						
							| 
									
										
										
										
											2020-03-27 14:06:48 -07:00
										 |  |  | 		// Existing record case. | 
					
						
							|  |  |  | 		existingRec := actual.(*record) | 
					
						
							|  |  |  | 		if existingRec.refMapped.ref() { | 
					
						
							| 
									
										
										
										
											2020-02-06 14:45:56 -08:00
										 |  |  | 			// At this moment it is guaranteed that the entry is in | 
					
						
							|  |  |  | 			// the map and will not be removed. | 
					
						
							| 
									
										
										
										
											2020-03-27 14:06:48 -07:00
										 |  |  | 			return existingRec | 
					
						
							| 
									
										
										
										
											2020-02-06 14:45:56 -08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		// This entry is no longer mapped, try to add a new entry. | 
					
						
							| 
									
										
										
										
											2019-11-06 10:54:36 -08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-27 14:06:48 -07:00
										 |  |  | 	if rec == nil { | 
					
						
							|  |  |  | 		rec = &record{} | 
					
						
							| 
									
										
										
										
											2020-04-23 12:10:58 -07:00
										 |  |  | 		rec.labels = labelPtr | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-03-27 14:06:48 -07:00
										 |  |  | 	rec.refMapped = refcountMapped{value: 2} | 
					
						
							|  |  |  | 	rec.inst = s | 
					
						
							| 
									
										
										
										
											2020-06-13 00:55:01 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-23 12:00:15 -07:00
										 |  |  | 	s.meter.processor.AggregatorFor(&s.descriptor, &rec.current, &rec.checkpoint) | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-06 14:45:56 -08:00
										 |  |  | 	for { | 
					
						
							|  |  |  | 		// Load/Store: there's a memory allocation to place `mk` into | 
					
						
							|  |  |  | 		// an interface here. | 
					
						
							| 
									
										
										
										
											2020-03-19 12:02:46 -07:00
										 |  |  | 		if actual, loaded := s.meter.current.LoadOrStore(mk, rec); loaded { | 
					
						
							| 
									
										
										
										
											2020-02-06 14:45:56 -08:00
										 |  |  | 			// Existing record case. Cannot change rec here because if fail | 
					
						
							|  |  |  | 			// will try to add rec again to avoid new allocations. | 
					
						
							|  |  |  | 			oldRec := actual.(*record) | 
					
						
							|  |  |  | 			if oldRec.refMapped.ref() { | 
					
						
							|  |  |  | 				// At this moment it is guaranteed that the entry is in | 
					
						
							|  |  |  | 				// the map and will not be removed. | 
					
						
							|  |  |  | 				return oldRec | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			// This loaded entry is marked as unmapped (so Collect will remove | 
					
						
							|  |  |  | 			// it from the map immediately), try again - this is a busy waiting | 
					
						
							|  |  |  | 			// strategy to wait until Collect() removes this entry from the map. | 
					
						
							|  |  |  | 			// | 
					
						
							|  |  |  | 			// This can be improved by having a list of "Unmapped" entries for | 
					
						
							|  |  |  | 			// one time only usages, OR we can make this a blocking path and use | 
					
						
							|  |  |  | 			// a Mutex that protects the delete operation (delete only if the old | 
					
						
							|  |  |  | 			// record is associated with the key). | 
					
						
							| 
									
										
										
										
											2020-02-10 16:20:29 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// Let collector get work done to remove the entry from the map. | 
					
						
							|  |  |  | 			runtime.Gosched() | 
					
						
							| 
									
										
										
										
											2020-02-06 14:45:56 -08:00
										 |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// The new entry was added to the map, good to go. | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | 		return rec | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-20 14:29:13 -07:00
										 |  |  | // The order of the input array `kvs` may be sorted after the function is called. | 
					
						
							| 
									
										
										
										
											2021-02-18 12:59:37 -05:00
										 |  |  | func (s *syncInstrument) Bind(kvs []attribute.KeyValue) metric.BoundSyncImpl { | 
					
						
							| 
									
										
										
										
											2020-03-27 14:06:48 -07:00
										 |  |  | 	return s.acquireHandle(kvs, nil) | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-20 14:29:13 -07:00
										 |  |  | // The order of the input array `kvs` may be sorted after the function is called. | 
					
						
							| 
									
										
										
										
											2021-02-18 12:59:37 -05:00
										 |  |  | func (s *syncInstrument) RecordOne(ctx context.Context, num number.Number, kvs []attribute.KeyValue) { | 
					
						
							| 
									
										
										
										
											2020-03-27 14:06:48 -07:00
										 |  |  | 	h := s.acquireHandle(kvs, nil) | 
					
						
							| 
									
										
										
										
											2019-12-27 16:30:19 -08:00
										 |  |  | 	defer h.Unbind() | 
					
						
							| 
									
										
										
										
											2020-11-11 16:24:12 +01:00
										 |  |  | 	h.RecordOne(ctx, num) | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-11 10:23:06 -07:00
										 |  |  | // NewAccumulator constructs a new Accumulator for the given | 
					
						
							| 
									
										
										
										
											2020-06-23 12:00:15 -07:00
										 |  |  | // processor.  This Accumulator supports only a single processor. | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2020-05-11 10:23:06 -07:00
										 |  |  | // The Accumulator does not start any background process to collect itself | 
					
						
							| 
									
										
										
										
											2020-12-16 01:06:58 +09:00
										 |  |  | // periodically, this responsibility lies with the processor, typically, | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | // depending on the type of export.  For example, a pull-based | 
					
						
							| 
									
										
										
										
											2020-06-23 12:00:15 -07:00
										 |  |  | // processor will call Collect() when it receives a request to scrape | 
					
						
							|  |  |  | // current metric values.  A push-based processor should configure its | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | // own periodic collection. | 
					
						
							| 
									
										
										
										
											2020-10-31 11:16:55 -07:00
										 |  |  | func NewAccumulator(processor export.Processor, resource *resource.Resource) *Accumulator { | 
					
						
							| 
									
										
										
										
											2020-05-11 10:23:06 -07:00
										 |  |  | 	return &Accumulator{ | 
					
						
							| 
									
										
										
										
											2020-06-23 12:00:15 -07:00
										 |  |  | 		processor:        processor, | 
					
						
							| 
									
										
										
										
											2020-06-02 11:30:09 -07:00
										 |  |  | 		asyncInstruments: internal.NewAsyncInstrumentState(), | 
					
						
							| 
									
										
										
										
											2020-10-31 11:16:55 -07:00
										 |  |  | 		resource:         resource, | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-12 16:28:32 +01:00
										 |  |  | // NewSyncInstrument implements metric.MetricImpl. | 
					
						
							|  |  |  | func (m *Accumulator) NewSyncInstrument(descriptor metric.Descriptor) (metric.SyncImpl, error) { | 
					
						
							| 
									
										
										
										
											2020-03-19 12:02:46 -07:00
										 |  |  | 	return &syncInstrument{ | 
					
						
							|  |  |  | 		instrument: instrument{ | 
					
						
							|  |  |  | 			descriptor: descriptor, | 
					
						
							|  |  |  | 			meter:      m, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2020-03-11 11:57:57 -07:00
										 |  |  | 	}, nil | 
					
						
							| 
									
										
										
										
											2020-03-05 12:15:30 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-12 16:28:32 +01:00
										 |  |  | // NewAsyncInstrument implements metric.MetricImpl. | 
					
						
							|  |  |  | func (m *Accumulator) NewAsyncInstrument(descriptor metric.Descriptor, runner metric.AsyncRunner) (metric.AsyncImpl, error) { | 
					
						
							| 
									
										
										
										
											2020-03-19 12:02:46 -07:00
										 |  |  | 	a := &asyncInstrument{ | 
					
						
							|  |  |  | 		instrument: instrument{ | 
					
						
							|  |  |  | 			descriptor: descriptor, | 
					
						
							|  |  |  | 			meter:      m, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2020-03-05 12:15:30 -08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-05-13 16:27:52 -07:00
										 |  |  | 	m.asyncLock.Lock() | 
					
						
							|  |  |  | 	defer m.asyncLock.Unlock() | 
					
						
							|  |  |  | 	m.asyncInstruments.Register(a, runner) | 
					
						
							| 
									
										
										
										
											2020-03-19 12:02:46 -07:00
										 |  |  | 	return a, nil | 
					
						
							| 
									
										
										
										
											2020-03-05 12:15:30 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Collect traverses the list of active records and observers and | 
					
						
							|  |  |  | // exports data for each active instrument.  Collect() may not be | 
					
						
							|  |  |  | // called concurrently. | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2020-06-23 12:00:15 -07:00
										 |  |  | // During the collection pass, the export.Processor will receive | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | // one Export() call per current aggregation. | 
					
						
							| 
									
										
										
										
											2019-11-15 13:01:20 -08:00
										 |  |  | // | 
					
						
							|  |  |  | // Returns the number of records that were checkpointed. | 
					
						
							| 
									
										
										
										
											2020-05-11 10:23:06 -07:00
										 |  |  | func (m *Accumulator) Collect(ctx context.Context) int { | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | 	m.collectLock.Lock() | 
					
						
							|  |  |  | 	defer m.collectLock.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-19 21:33:10 -07:00
										 |  |  | 	checkpointed := m.observeAsyncInstruments(ctx) | 
					
						
							| 
									
										
										
										
											2020-06-09 11:00:50 -07:00
										 |  |  | 	checkpointed += m.collectSyncInstruments() | 
					
						
							| 
									
										
										
										
											2020-03-05 12:15:30 -08:00
										 |  |  | 	m.currentEpoch++ | 
					
						
							| 
									
										
										
										
											2020-05-18 18:37:41 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-05 12:15:30 -08:00
										 |  |  | 	return checkpointed | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-09 11:00:50 -07:00
										 |  |  | func (m *Accumulator) collectSyncInstruments() int { | 
					
						
							| 
									
										
										
										
											2019-11-15 13:01:20 -08:00
										 |  |  | 	checkpointed := 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-06 14:45:56 -08:00
										 |  |  | 	m.current.Range(func(key interface{}, value interface{}) bool { | 
					
						
							| 
									
										
										
										
											2020-04-21 20:23:15 -07:00
										 |  |  | 		// Note: always continue to iterate over the entire | 
					
						
							|  |  |  | 		// map by returning `true` in this function. | 
					
						
							| 
									
										
										
										
											2020-02-06 14:45:56 -08:00
										 |  |  | 		inuse := value.(*record) | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-21 20:23:15 -07:00
										 |  |  | 		mods := atomic.LoadInt64(&inuse.updateCount) | 
					
						
							|  |  |  | 		coll := inuse.collectedCount | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if mods != coll { | 
					
						
							|  |  |  | 			// Updates happened in this interval, | 
					
						
							|  |  |  | 			// checkpoint and continue. | 
					
						
							| 
									
										
										
										
											2020-06-09 11:00:50 -07:00
										 |  |  | 			checkpointed += m.checkpointRecord(inuse) | 
					
						
							| 
									
										
										
										
											2020-04-21 20:23:15 -07:00
										 |  |  | 			inuse.collectedCount = mods | 
					
						
							|  |  |  | 			return true | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-21 20:23:15 -07:00
										 |  |  | 		// Having no updates since last collection, try to unmap: | 
					
						
							|  |  |  | 		if unmapped := inuse.refMapped.tryUnmap(); !unmapped { | 
					
						
							|  |  |  | 			// The record is referenced by a binding, continue. | 
					
						
							|  |  |  | 			return true | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// If any other goroutines are now trying to re-insert this | 
					
						
							|  |  |  | 		// entry in the map, they are busy calling Gosched() awaiting | 
					
						
							|  |  |  | 		// this deletion: | 
					
						
							|  |  |  | 		m.current.Delete(inuse.mapkey()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// There's a potential race between `LoadInt64` and | 
					
						
							|  |  |  | 		// `tryUnmap` in this function.  Since this is the | 
					
						
							|  |  |  | 		// last we'll see of this record, checkpoint | 
					
						
							|  |  |  | 		mods = atomic.LoadInt64(&inuse.updateCount) | 
					
						
							|  |  |  | 		if mods != coll { | 
					
						
							| 
									
										
										
										
											2020-06-09 11:00:50 -07:00
										 |  |  | 			checkpointed += m.checkpointRecord(inuse) | 
					
						
							| 
									
										
										
										
											2020-04-21 20:23:15 -07:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-02-06 14:45:56 -08:00
										 |  |  | 		return true | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-15 13:01:20 -08:00
										 |  |  | 	return checkpointed | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-13 16:27:52 -07:00
										 |  |  | // CollectAsync implements internal.AsyncCollector. | 
					
						
							| 
									
										
										
										
											2021-04-20 14:29:13 -07:00
										 |  |  | // The order of the input array `kvs` may be sorted after the function is called. | 
					
						
							| 
									
										
										
										
											2021-02-18 12:59:37 -05:00
										 |  |  | func (m *Accumulator) CollectAsync(kv []attribute.KeyValue, obs ...metric.Observation) { | 
					
						
							|  |  |  | 	labels := attribute.NewSetWithSortable(kv, &m.asyncSortSlice) | 
					
						
							| 
									
										
										
										
											2020-03-05 12:15:30 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-13 16:27:52 -07:00
										 |  |  | 	for _, ob := range obs { | 
					
						
							| 
									
										
										
										
											2020-05-20 10:19:51 -07:00
										 |  |  | 		if a := m.fromAsync(ob.AsyncImpl()); a != nil { | 
					
						
							|  |  |  | 			a.observe(ob.Number(), &labels) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-05-13 16:27:52 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-03-05 12:15:30 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-13 16:27:52 -07:00
										 |  |  | func (m *Accumulator) observeAsyncInstruments(ctx context.Context) int { | 
					
						
							|  |  |  | 	m.asyncLock.Lock() | 
					
						
							|  |  |  | 	defer m.asyncLock.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	asyncCollected := 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-13 14:07:44 -08:00
										 |  |  | 	m.asyncInstruments.Run(ctx, m) | 
					
						
							| 
									
										
										
										
											2020-05-13 16:27:52 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for _, inst := range m.asyncInstruments.Instruments() { | 
					
						
							| 
									
										
										
										
											2020-05-20 10:19:51 -07:00
										 |  |  | 		if a := m.fromAsync(inst); a != nil { | 
					
						
							|  |  |  | 			asyncCollected += m.checkpointAsync(a) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-05-13 16:27:52 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return asyncCollected | 
					
						
							| 
									
										
										
										
											2020-03-05 12:15:30 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-09 11:00:50 -07:00
										 |  |  | func (m *Accumulator) checkpointRecord(r *record) int { | 
					
						
							| 
									
										
										
										
											2020-06-13 00:55:01 -07:00
										 |  |  | 	if r.current == nil { | 
					
						
							|  |  |  | 		return 0 | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-06-23 10:41:11 -07:00
										 |  |  | 	err := r.current.SynchronizedMove(r.checkpoint, &r.inst.descriptor) | 
					
						
							| 
									
										
										
										
											2020-06-13 00:55:01 -07:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-11-16 18:30:54 +01:00
										 |  |  | 		otel.Handle(err) | 
					
						
							| 
									
										
										
										
											2020-06-13 00:55:01 -07:00
										 |  |  | 		return 0 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-18 10:16:33 -07:00
										 |  |  | 	a := export.NewAccumulation(&r.inst.descriptor, r.labels, m.resource, r.checkpoint) | 
					
						
							| 
									
										
										
										
											2020-06-23 12:00:15 -07:00
										 |  |  | 	err = m.processor.Process(a) | 
					
						
							| 
									
										
										
										
											2020-06-13 00:55:01 -07:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-11-16 18:30:54 +01:00
										 |  |  | 		otel.Handle(err) | 
					
						
							| 
									
										
										
										
											2020-06-13 00:55:01 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return 1 | 
					
						
							| 
									
										
										
										
											2020-03-05 12:15:30 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-13 16:27:52 -07:00
										 |  |  | func (m *Accumulator) checkpointAsync(a *asyncInstrument) int { | 
					
						
							| 
									
										
										
										
											2020-03-19 12:02:46 -07:00
										 |  |  | 	if len(a.recorders) == 0 { | 
					
						
							| 
									
										
										
										
											2019-11-15 13:01:20 -08:00
										 |  |  | 		return 0 | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-03-05 12:15:30 -08:00
										 |  |  | 	checkpointed := 0 | 
					
						
							| 
									
										
										
										
											2020-03-19 12:02:46 -07:00
										 |  |  | 	for encodedLabels, lrec := range a.recorders { | 
					
						
							| 
									
										
										
										
											2020-03-27 14:06:48 -07:00
										 |  |  | 		lrec := lrec | 
					
						
							| 
									
										
										
										
											2020-04-21 20:23:15 -07:00
										 |  |  | 		epochDiff := m.currentEpoch - lrec.observedEpoch | 
					
						
							| 
									
										
										
										
											2020-03-05 12:15:30 -08:00
										 |  |  | 		if epochDiff == 0 { | 
					
						
							| 
									
										
										
										
											2020-06-13 00:55:01 -07:00
										 |  |  | 			if lrec.observed != nil { | 
					
						
							| 
									
										
										
										
											2020-06-18 10:16:33 -07:00
										 |  |  | 				a := export.NewAccumulation(&a.descriptor, lrec.labels, m.resource, lrec.observed) | 
					
						
							| 
									
										
										
										
											2020-06-23 12:00:15 -07:00
										 |  |  | 				err := m.processor.Process(a) | 
					
						
							| 
									
										
										
										
											2020-06-13 00:55:01 -07:00
										 |  |  | 				if err != nil { | 
					
						
							| 
									
										
										
										
											2020-11-16 18:30:54 +01:00
										 |  |  | 					otel.Handle(err) | 
					
						
							| 
									
										
										
										
											2020-06-13 00:55:01 -07:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				checkpointed++ | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2020-03-05 12:15:30 -08:00
										 |  |  | 		} else if epochDiff > 1 { | 
					
						
							|  |  |  | 			// This is second collection cycle with no | 
					
						
							|  |  |  | 			// observations for this labelset. Remove the | 
					
						
							|  |  |  | 			// recorder. | 
					
						
							| 
									
										
										
										
											2020-03-19 12:02:46 -07:00
										 |  |  | 			delete(a.recorders, encodedLabels) | 
					
						
							| 
									
										
										
										
											2020-03-05 12:15:30 -08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-03-19 12:02:46 -07:00
										 |  |  | 	if len(a.recorders) == 0 { | 
					
						
							|  |  |  | 		a.recorders = nil | 
					
						
							| 
									
										
										
										
											2020-03-05 12:15:30 -08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return checkpointed | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-11-15 13:01:20 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | // RecordBatch enters a batch of metric events. | 
					
						
							| 
									
										
										
										
											2021-04-20 14:29:13 -07:00
										 |  |  | // The order of the input array `kvs` may be sorted after the function is called. | 
					
						
							| 
									
										
										
										
											2021-02-18 12:59:37 -05:00
										 |  |  | func (m *Accumulator) RecordBatch(ctx context.Context, kvs []attribute.KeyValue, measurements ...metric.Measurement) { | 
					
						
							| 
									
										
										
										
											2020-03-27 14:06:48 -07:00
										 |  |  | 	// Labels will be computed the first time acquireHandle is | 
					
						
							|  |  |  | 	// called.  Subsequent calls to acquireHandle will re-use the | 
					
						
							|  |  |  | 	// previously computed value instead of recomputing the | 
					
						
							|  |  |  | 	// ordered labels. | 
					
						
							| 
									
										
										
										
											2021-02-18 12:59:37 -05:00
										 |  |  | 	var labelsPtr *attribute.Set | 
					
						
							| 
									
										
										
										
											2020-03-27 14:06:48 -07:00
										 |  |  | 	for i, meas := range measurements { | 
					
						
							| 
									
										
										
										
											2020-05-20 10:19:51 -07:00
										 |  |  | 		s := m.fromSync(meas.SyncImpl()) | 
					
						
							|  |  |  | 		if s == nil { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-04-23 12:10:58 -07:00
										 |  |  | 		h := s.acquireHandle(kvs, labelsPtr) | 
					
						
							| 
									
										
										
										
											2020-03-27 14:06:48 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// Re-use labels for the next measurement. | 
					
						
							|  |  |  | 		if i == 0 { | 
					
						
							| 
									
										
										
										
											2020-04-23 12:10:58 -07:00
										 |  |  | 			labelsPtr = h.labels | 
					
						
							| 
									
										
										
										
											2020-03-27 14:06:48 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		defer h.Unbind() | 
					
						
							|  |  |  | 		h.RecordOne(ctx, meas.Number()) | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-12 16:28:32 +01:00
										 |  |  | // RecordOne implements metric.SyncImpl. | 
					
						
							| 
									
										
										
										
											2020-11-11 16:24:12 +01:00
										 |  |  | func (r *record) RecordOne(ctx context.Context, num number.Number) { | 
					
						
							| 
									
										
										
										
											2020-06-13 00:55:01 -07:00
										 |  |  | 	if r.current == nil { | 
					
						
							| 
									
										
										
										
											2020-06-23 10:51:15 -07:00
										 |  |  | 		// The instrument is disabled according to the AggregatorSelector. | 
					
						
							| 
									
										
										
										
											2019-11-15 13:01:20 -08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-11-11 16:24:12 +01:00
										 |  |  | 	if err := aggregator.RangeTest(num, &r.inst.descriptor); err != nil { | 
					
						
							| 
									
										
										
										
											2020-11-16 18:30:54 +01:00
										 |  |  | 		otel.Handle(err) | 
					
						
							| 
									
										
										
										
											2019-11-15 13:01:20 -08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-11-11 16:24:12 +01:00
										 |  |  | 	if err := r.current.Update(ctx, num, &r.inst.descriptor); err != nil { | 
					
						
							| 
									
										
										
										
											2020-11-16 18:30:54 +01:00
										 |  |  | 		otel.Handle(err) | 
					
						
							| 
									
										
										
										
											2019-11-15 13:01:20 -08:00
										 |  |  | 		return | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-04-21 20:23:15 -07:00
										 |  |  | 	// Record was modified, inform the Collect() that things need | 
					
						
							|  |  |  | 	// to be collected while the record is still mapped. | 
					
						
							|  |  |  | 	atomic.AddInt64(&r.updateCount, 1) | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-12 16:28:32 +01:00
										 |  |  | // Unbind implements metric.SyncImpl. | 
					
						
							| 
									
										
										
										
											2019-12-27 16:30:19 -08:00
										 |  |  | func (r *record) Unbind() { | 
					
						
							| 
									
										
										
										
											2020-02-06 14:45:56 -08:00
										 |  |  | 	r.refMapped.unref() | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (r *record) mapkey() mapkey { | 
					
						
							|  |  |  | 	return mapkey{ | 
					
						
							| 
									
										
										
										
											2020-03-19 12:02:46 -07:00
										 |  |  | 		descriptor: &r.inst.descriptor, | 
					
						
							| 
									
										
										
										
											2020-04-23 12:10:58 -07:00
										 |  |  | 		ordered:    r.labels.Equivalent(), | 
					
						
							| 
									
										
										
										
											2019-10-29 13:27:22 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-05-20 10:19:51 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | // fromSync gets a sync implementation object, checking for | 
					
						
							|  |  |  | // uninitialized instruments and instruments created by another SDK. | 
					
						
							| 
									
										
										
										
											2020-11-12 16:28:32 +01:00
										 |  |  | func (m *Accumulator) fromSync(sync metric.SyncImpl) *syncInstrument { | 
					
						
							| 
									
										
										
										
											2020-05-20 10:19:51 -07:00
										 |  |  | 	if sync != nil { | 
					
						
							|  |  |  | 		if inst, ok := sync.Implementation().(*syncInstrument); ok { | 
					
						
							|  |  |  | 			return inst | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-11-16 18:30:54 +01:00
										 |  |  | 	otel.Handle(ErrUninitializedInstrument) | 
					
						
							| 
									
										
										
										
											2020-05-20 10:19:51 -07:00
										 |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // fromSync gets an async implementation object, checking for | 
					
						
							|  |  |  | // uninitialized instruments and instruments created by another SDK. | 
					
						
							| 
									
										
										
										
											2020-11-12 16:28:32 +01:00
										 |  |  | func (m *Accumulator) fromAsync(async metric.AsyncImpl) *asyncInstrument { | 
					
						
							| 
									
										
										
										
											2020-05-20 10:19:51 -07:00
										 |  |  | 	if async != nil { | 
					
						
							|  |  |  | 		if inst, ok := async.Implementation().(*asyncInstrument); ok { | 
					
						
							|  |  |  | 			return inst | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-11-16 18:30:54 +01:00
										 |  |  | 	otel.Handle(ErrUninitializedInstrument) | 
					
						
							| 
									
										
										
										
											2020-05-20 10:19:51 -07:00
										 |  |  | 	return nil | 
					
						
							|  |  |  | } |