Skip to content

Commit

Permalink
DEV: add queryMetrics to query multiple metrics
Browse files Browse the repository at this point in the history
  • Loading branch information
dev-embedthis committed Jan 1, 2025
1 parent 5c93abb commit ac5c345
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 16 deletions.
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ let results = await metrics.query('Acme/Metrics', 'speed', {
}, 86400, 'max')
```

This will retrieve the `speed` metric from the `Acme/Metrics` namespace for the `{rocket == 'saturnV'}` dimension. The data points returned will be the maximum speed measured over the day's launches (86400 seconds). Intervals that have no data will have points set to {count: 0, value: 0, timestamp}.
This will retrieve the `speed` metric from the `Acme/Metrics` namespace for the `{rocket == 'saturnV'}` dimension. The data points returned will be the maximum speed measured over the day's launches (86400 seconds). Intervals that have no data will have points set to {count: 0, value: 0, timestamp}. Use {} for the all-dimensions value.

This will return data like this:

Expand Down Expand Up @@ -171,14 +171,22 @@ let results = await metrics.query('Acme/Metrics', 'speed', {

This will return a single maximum speed over the last day.

The following will do the same but from a given start date and evaluate 28 days of data.
The following will do the same but from a specific start date.

```javascript
let results = await metrics.query('Acme/Metrics', 'speed', {
rocket: 'saturnV'
}, 28 * 86400, 'max', {accumulate: true, start: new Date(2000, 0, 1).getTime()})
```

To query multiple metrics, use the `queryMetrics` method. This will query all dimensions for a metric and
return a list of metric results for all dimensions. Note: this will not flush buffered metric values before computing the results.

```javascript
let results = await metrics.queryMetrics('Acme/Metrics', 'speed', 86400, 'avg')
```


To obtain a list of metrics, use the `getMetricList` method:

```typescript
Expand Down
82 changes: 68 additions & 14 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ export type MetricListOptions = {
limit?: number
owner?: string
next?: object
timestamp?: number
}

export type MetricQueryOptions = {
Expand Down Expand Up @@ -601,8 +602,8 @@ export class CustomMetrics {
let now = Math.floor((options.timestamp || Date.now()) / 1000)

/*
Flush buffered metrics for this instance. Will still not see buffered metrics in
other instances until they are flushed.
Flush buffered metrics for this instance. Will not see buffered metrics in other instances
until they are flushed.
*/
if (this.buffers) {
let key = this.getBufferKey(namespace, metricName, dimString)
Expand All @@ -614,9 +615,66 @@ export class CustomMetrics {
if (!metric) {
return {dimensions, id: options.id, metric: metricName, namespace, period, points: [], owner, samples: 0}
}
let result = this.processMetric(metric, now, period, statistic, options)

/* istanbul ignore next */
this.log[options.log == true ? 'info' : 'trace'](`Query metrics ${namespace}, ${metricName}`, {
dimensions,
period,
statistic,
options,
result,
})
return result
}

async queryMetrics(
namespace: string,
metric: string | undefined,
period: number,
statistic: string,
options: MetricListOptions = {}
): Promise<MetricQueryResult[]> {
let owner = options.owner || this.owner
let next: object | undefined = options.next
let limit = options.limit || MetricListLimit
/* istanbul ignore next */
let chan = options.log == true ? 'info' : 'trace'
let items, command
let count = 0
do {
/* istanbul ignore next */
;({command, items, next} = await this.findMetrics(owner, namespace, metric, limit, next, 'spans'))
this.log[chan](`Find metrics ${namespace}, ${metric}`, {command, items})
if (items.length) {
count += items.length
}
} while (next && count < limit)

let now = Math.floor((options.timestamp || Date.now()) / 1000)

let results = []
for (let metric of items) {
let result = this.processMetric(metric, now, period, statistic, {accumulate: true, timestamp: now})
results.push(result)
}
return results
}

/*
Process a metric for query() or queryMetrics() and extract the desired series or accumlated value
*/
processMetric(
metric: Metric,
now: number,
period: number,
statistic: string,
options: MetricQueryOptions
): MetricQueryResult {
let end: number
let si: number
let owner = options.owner || this.owner

if (options.start) {
/*
Find span for the request start: period < span[i+1].period
Expand All @@ -641,8 +699,7 @@ export class CustomMetrics {
si = metric.spans.length - 1
}
/*
Aggregate data for all spans up to the desired span.
Do this because spans are updated lazily on emit.
Aggregate data for all spans up to the desired span. Do this because spans are updated lazily on emit.
*/
this.addValue(metric, now, {count: 0, sum: 0}, 0, si)

Expand All @@ -654,14 +711,6 @@ export class CustomMetrics {
result = this.calculateSeries(metric, span, statistic, owner, end, period)
}
result.id = options.id
/* istanbul ignore next */
this.log[options.log == true ? 'info' : 'trace'](`Query metrics ${namespace}, ${metricName}`, {
dimensions,
period,
statistic,
options,
result,
})
return result
}

Expand Down Expand Up @@ -1120,7 +1169,8 @@ export class CustomMetrics {
namespace: string,
metric: string | undefined,
limit: number,
startKey: object
startKey: object,
fields: string = ''
): Promise<{items: Metric[]; next: object; command: QueryCommand}> {
let key = [namespace]
if (metric) {
Expand All @@ -1129,6 +1179,10 @@ export class CustomMetrics {
/* istanbul ignore next */

let start = startKey ? marshall(startKey) : undefined
let project = `${this.primaryKey}, ${this.sortKey}`
if (fields) {
project += `, ${fields}`
}
let command = new QueryCommand({
TableName: this.table,
ExpressionAttributeNames: {
Expand All @@ -1144,7 +1198,7 @@ export class CustomMetrics {
Limit: limit,
ScanIndexForward: true,
ExclusiveStartKey: start,
ProjectionExpression: `${this.primaryKey}, ${this.sortKey}`,
ProjectionExpression: project,
})

let result = await this.client.send(command)
Expand Down

0 comments on commit ac5c345

Please sign in to comment.