-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: slightly configurable line writer
- Loading branch information
1 parent
5482cc3
commit d09aa16
Showing
2 changed files
with
216 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
import {mocked} from 'ts-jest/utils' | ||
|
||
jest.mock('src/utils/ajax') | ||
import { | ||
createLineFromModel, | ||
buildLineWriter, | ||
Precision, | ||
} from 'src/utils/lineWriter' | ||
|
||
import MockAjax from 'src/utils/ajax' | ||
|
||
describe('creating a line from a model', () => { | ||
it('creates a line without tags', () => { | ||
const measurement = 'performance' | ||
const tags = {} | ||
const fields = {fps: 55} | ||
const timestamp = 1584990314 | ||
|
||
const line = createLineFromModel(measurement, fields, tags, timestamp) | ||
expect(line).toBe('performance fps=55 1584990314') | ||
}) | ||
|
||
it('creates a line when no tags are passed in', () => { | ||
const measurement = 'performance' | ||
const fields = {fps: 55} | ||
|
||
const line = createLineFromModel(measurement, fields) | ||
expect(line).toEqual(expect.stringContaining('performance fps=55')) | ||
}) | ||
|
||
it('creates a line without tags with multiple fields', () => { | ||
const measurement = 'performance' | ||
const tags = {} | ||
const fields = {fps: 49.33333, heap: 48577273} | ||
const timestamp = 1584990314 | ||
|
||
const line = createLineFromModel(measurement, fields, tags, timestamp) | ||
expect(line).toBe('performance fps=49.33333,heap=48577273 1584990314') | ||
}) | ||
|
||
it('creates a line with a tag', () => { | ||
const measurement = 'performance' | ||
const tags = {region: 'us-west'} | ||
const fields = {fps: 49.33333, heap: 48577273} | ||
const timestamp = 1584990314 | ||
|
||
const line = createLineFromModel(measurement, fields, tags, timestamp) | ||
expect(line).toBe( | ||
'performance,region=us-west fps=49.33333,heap=48577273 1584990314' | ||
) | ||
}) | ||
|
||
it('creates a line with multiple tags', () => { | ||
const measurement = 'performance' | ||
const tags = {region: 'us-west', status: 'good'} | ||
const fields = {fps: 49.33333, heap: 48577273} | ||
const timestamp = 1584990314 | ||
|
||
const line = createLineFromModel(measurement, fields, tags, timestamp) | ||
expect(line).toBe( | ||
'performance,region=us-west,status=good fps=49.33333,heap=48577273 1584990314' | ||
) | ||
}) | ||
|
||
it('alphabetizes tags by key, for write optimization', () => { | ||
const measurement = 'performance' | ||
const tags = {region: 'us-west', environment: 'dev'} | ||
const fields = {fps: 49.33333, heap: 48577273} | ||
const timestamp = 1584990314 | ||
|
||
const line = createLineFromModel(measurement, fields, tags, timestamp) | ||
expect(line).toBe( | ||
'performance,environment=dev,region=us-west fps=49.33333,heap=48577273 1584990314' | ||
) | ||
}) | ||
}) | ||
|
||
describe('building a line writer', () => { | ||
const url = 'https://west-west-west.cloud2.influxdata.com' | ||
const orgId = '823723asdfc92134' | ||
const bucketName = 'performance' | ||
const authToken = 'asdf2#%JASjasg==' | ||
|
||
it('builds a line writer with the passed in properties', () => { | ||
const writeLine = buildLineWriter(url, orgId, bucketName, authToken) | ||
|
||
const measurement = 'performance' | ||
const tags = {region: 'us-west', environment: 'dev'} | ||
const fields = {fps: 55.583583242, timeInFrame: 15} | ||
const timestamp = 1585005787 | ||
|
||
writeLine(measurement, fields, tags, Precision.s, timestamp) | ||
const [requestParams, shouldExcludeBasepath] = mocked( | ||
MockAjax | ||
).mock.calls[0] | ||
|
||
expect(shouldExcludeBasepath).toBeTruthy() | ||
expect(requestParams).toEqual({ | ||
method: 'POST', | ||
url: `${url}/api/v2/write`, | ||
data: createLineFromModel(measurement, fields, tags, timestamp), | ||
headers: { | ||
Authorization: `Token ${authToken}`, | ||
}, | ||
params: { | ||
org: orgId, | ||
bucket: bucketName, | ||
precision: Precision.s, | ||
}, | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import AJAX from 'src/utils/ajax' | ||
|
||
export interface Tags { | ||
[key: string]: string | number | ||
} | ||
|
||
export interface Fields { | ||
[key: string]: number | string | ||
} | ||
|
||
export enum Precision { | ||
ns = 'ns', | ||
u = 'u', | ||
ms = 'ms', | ||
s = 's', | ||
m = 'm', | ||
h = 'h', | ||
} | ||
|
||
const nowInSeconds = function nowInSeconds() { | ||
return Math.floor(Date.now() / 1000) | ||
} | ||
|
||
// Build a line writer that can write arbitrary line data | ||
export const createLineFromModel = function createLineFromModel( | ||
measurement: string, | ||
fields: Fields, | ||
tags: Tags = {}, | ||
timestamp: number = nowInSeconds() | ||
): string { | ||
let tagString = '' | ||
Object.keys(tags) | ||
// Sort keys for a little extra perf | ||
// https://v2.docs.influxdata.com/v2.0/write-data/best-practices/optimize-writes/#sort-tags-by-key | ||
.sort() | ||
.forEach((tagKey, i, tagKeys) => { | ||
const tagValue = tags[tagKey] | ||
tagString = `${tagString}${tagKey}=${tagValue}` | ||
|
||
// if this isn't the end of the string, append a comma | ||
if (i < tagKeys.length - 1) { | ||
tagString = `${tagString},` | ||
} | ||
}) | ||
|
||
let fieldString = '' | ||
Object.keys(fields).forEach((fieldKey, i, fieldKeys) => { | ||
const fieldValue = fields[fieldKey] | ||
fieldString = `${fieldString}${fieldKey}=${fieldValue}` | ||
|
||
// if this isn't the end of the string, append a comma | ||
if (i < fieldKeys.length - 1) { | ||
fieldString = `${fieldString},` | ||
} | ||
}) | ||
|
||
let lineStart = measurement | ||
if (tagString !== '') { | ||
lineStart = `${lineStart},${tagString}` | ||
} | ||
|
||
return `${lineStart} ${fieldString} ${timestamp}` | ||
} | ||
|
||
// Builds a basic line writer that will write a line to the url, org and bucket specified. | ||
// Returns a function named `writeLine` that utilizes closures to access the configuration | ||
// arguments passed in to `buildLineWriter`. | ||
export const buildLineWriter = function buildLineWriter( | ||
url: string, | ||
orgId: number | string, | ||
bucketName: string, | ||
authToken: string | ||
) { | ||
return async function writeLine( | ||
measurement: string, | ||
fields: Fields, | ||
tags: Tags = {}, | ||
precision: Precision = Precision.s, | ||
timestamp: number = nowInSeconds() | ||
) { | ||
const line = createLineFromModel(measurement, fields, tags, timestamp) | ||
|
||
try { | ||
await AJAX( | ||
{ | ||
method: 'POST', | ||
url: `${url}/api/v2/write`, | ||
data: line, | ||
headers: { | ||
Authorization: `Token ${authToken}`, | ||
}, | ||
params: { | ||
org: orgId, | ||
bucket: bucketName, | ||
precision, | ||
}, | ||
}, | ||
true | ||
) | ||
} catch (error) { | ||
console.error(error) | ||
} | ||
} | ||
} |