1 | "use strict";
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 | Object.defineProperty(exports, "__esModule", { value: true });
|
18 | const defaultLogger = require("../common/console-logger");
|
19 | const time_util_1 = require("../common/time-util");
|
20 | const types_1 = require("../metrics/export/types");
|
21 | const validation_1 = require("../tags/validation");
|
22 | const bucket_boundaries_1 = require("./bucket-boundaries");
|
23 | const metric_utils_1 = require("./metric-utils");
|
24 | const recorder_1 = require("./recorder");
|
25 | const types_2 = require("./types");
|
26 | const RECORD_SEPARATOR = String.fromCharCode(30);
|
27 |
|
28 |
|
29 |
|
30 |
|
31 | class BaseView {
|
32 | |
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 | constructor(name, measure, aggregation, tagsKeys, description, bucketBoundaries, logger = defaultLogger) {
|
45 | |
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 | this.tagValueAggregationMap = {};
|
52 |
|
53 | this.registered = false;
|
54 | if (aggregation === types_2.AggregationType.DISTRIBUTION && !bucketBoundaries) {
|
55 | throw new Error('No bucketBoundaries specified');
|
56 | }
|
57 | this.logger = logger.logger();
|
58 | this.name = name;
|
59 | this.description = description;
|
60 | this.measure = measure;
|
61 | this.columns = this.validateTagKeys(tagsKeys);
|
62 | this.aggregation = aggregation;
|
63 | this.startTime = Date.now();
|
64 | if (bucketBoundaries) {
|
65 | this.bucketBoundaries = new bucket_boundaries_1.BucketBoundaries(bucketBoundaries);
|
66 | }
|
67 | this.metricDescriptor = metric_utils_1.MetricUtils.viewToMetricDescriptor(this);
|
68 | }
|
69 |
|
70 | getColumns() {
|
71 | return this.columns;
|
72 | }
|
73 | |
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 |
|
83 |
|
84 | recordMeasurement(measurement, tags, attachments) {
|
85 | const tagValues = recorder_1.Recorder.getTagValues(tags.tags, this.columns);
|
86 | const encodedTags = this.encodeTagValues(tagValues);
|
87 | if (!this.tagValueAggregationMap[encodedTags]) {
|
88 | this.tagValueAggregationMap[encodedTags] = this.createAggregationData(tagValues);
|
89 | }
|
90 | recorder_1.Recorder.addMeasurement(this.tagValueAggregationMap[encodedTags], measurement, attachments);
|
91 | }
|
92 | |
93 |
|
94 |
|
95 |
|
96 | encodeTagValues(tagValues) {
|
97 | return tagValues
|
98 | .map(tagValue => (tagValue ? tagValue.value : null))
|
99 | .sort()
|
100 | .join(RECORD_SEPARATOR);
|
101 | }
|
102 | |
103 |
|
104 |
|
105 |
|
106 | createAggregationData(tagValues) {
|
107 | const aggregationMetadata = { tagValues, timestamp: Date.now() };
|
108 | switch (this.aggregation) {
|
109 | case types_2.AggregationType.DISTRIBUTION:
|
110 | const { buckets, bucketCounts } = this.bucketBoundaries;
|
111 | const bucketsCopy = Object.assign([], buckets);
|
112 | const bucketCountsCopy = Object.assign([], bucketCounts);
|
113 | const exemplars = new Array(bucketCounts.length);
|
114 | return Object.assign({}, aggregationMetadata, { type: types_2.AggregationType.DISTRIBUTION, startTime: this.startTime, count: 0, sum: 0, mean: 0, stdDeviation: 0, sumOfSquaredDeviation: 0, buckets: bucketsCopy, bucketCounts: bucketCountsCopy, exemplars });
|
115 | case types_2.AggregationType.SUM:
|
116 | return Object.assign({}, aggregationMetadata, { type: types_2.AggregationType.SUM, value: 0 });
|
117 | case types_2.AggregationType.COUNT:
|
118 | return Object.assign({}, aggregationMetadata, { type: types_2.AggregationType.COUNT, value: 0 });
|
119 | default:
|
120 | return Object.assign({}, aggregationMetadata, { type: types_2.AggregationType.LAST_VALUE, value: 0 });
|
121 | }
|
122 | }
|
123 | |
124 |
|
125 |
|
126 |
|
127 |
|
128 | getMetric(start) {
|
129 | const { type } = this.metricDescriptor;
|
130 | let startTimestamp;
|
131 |
|
132 | const now = time_util_1.getTimestampWithProcessHRTime();
|
133 | if (type !== types_1.MetricDescriptorType.GAUGE_INT64 &&
|
134 | type !== types_1.MetricDescriptorType.GAUGE_DOUBLE) {
|
135 | startTimestamp = time_util_1.timestampFromMillis(start);
|
136 | }
|
137 | const timeseries = [];
|
138 | Object.keys(this.tagValueAggregationMap).forEach(key => {
|
139 | const { tagValues } = this.tagValueAggregationMap[key];
|
140 | const labelValues = metric_utils_1.MetricUtils.tagValuesToLabelValues(tagValues);
|
141 | const point = this.toPoint(now, this.getSnapshot(tagValues));
|
142 | if (startTimestamp) {
|
143 | timeseries.push({ startTimestamp, labelValues, points: [point] });
|
144 | }
|
145 | else {
|
146 | timeseries.push({ labelValues, points: [point] });
|
147 | }
|
148 | });
|
149 | return { descriptor: this.metricDescriptor, timeseries };
|
150 | }
|
151 | |
152 |
|
153 |
|
154 |
|
155 |
|
156 |
|
157 | toPoint(timestamp, data) {
|
158 | if (data.type === types_2.AggregationType.DISTRIBUTION) {
|
159 | const { count, sum, sumOfSquaredDeviation, exemplars } = data;
|
160 | const buckets = [];
|
161 | if (data.bucketCounts) {
|
162 | for (let bucket = 0; bucket < data.bucketCounts.length; bucket++) {
|
163 | const bucketCount = data.bucketCounts[bucket];
|
164 | const statsExemplar = exemplars ? exemplars[bucket] : undefined;
|
165 | buckets.push(this.getMetricBucket(bucketCount, statsExemplar));
|
166 | }
|
167 | }
|
168 | const value = {
|
169 | count,
|
170 | sum,
|
171 | sumOfSquaredDeviation,
|
172 | buckets,
|
173 | bucketOptions: { explicit: { bounds: data.buckets } },
|
174 | };
|
175 | return { timestamp, value };
|
176 | }
|
177 | else {
|
178 | const value = data.value;
|
179 | return { timestamp, value };
|
180 | }
|
181 | }
|
182 | |
183 |
|
184 |
|
185 |
|
186 |
|
187 | getSnapshot(tagValues) {
|
188 | return this.tagValueAggregationMap[this.encodeTagValues(tagValues)];
|
189 | }
|
190 |
|
191 | getMetricBucket(bucketCount, statsExemplar) {
|
192 | if (statsExemplar) {
|
193 |
|
194 | return {
|
195 | count: bucketCount,
|
196 | exemplar: {
|
197 | value: statsExemplar.value,
|
198 | timestamp: time_util_1.timestampFromMillis(statsExemplar.timestamp),
|
199 | attachments: statsExemplar.attachments,
|
200 | },
|
201 | };
|
202 | }
|
203 |
|
204 | return { count: bucketCount };
|
205 | }
|
206 |
|
207 | validateTagKeys(tagKeys) {
|
208 | const tagKeysCopy = Object.assign([], tagKeys);
|
209 | tagKeysCopy.forEach(tagKey => {
|
210 | if (!validation_1.isValidTagKey(tagKey)) {
|
211 | throw new Error(`Invalid TagKey name: ${tagKey}`);
|
212 | }
|
213 | });
|
214 | const tagKeysSet = new Set(tagKeysCopy.map((tagKey) => tagKey.name));
|
215 | if (tagKeysSet.size !== tagKeysCopy.length) {
|
216 | throw new Error('Columns have duplicate');
|
217 | }
|
218 | return tagKeysCopy;
|
219 | }
|
220 | }
|
221 | exports.BaseView = BaseView;
|
222 |
|
\ | No newline at end of file |