Skip to content

Commit

Permalink
feat: slightly configurable line writer
Browse files Browse the repository at this point in the history
  • Loading branch information
hoorayimhelping committed Mar 24, 2020
1 parent 5482cc3 commit d09aa16
Show file tree
Hide file tree
Showing 2 changed files with 216 additions and 0 deletions.
112 changes: 112 additions & 0 deletions ui/src/utils/lineWriter.test.ts
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,
},
})
})
})
104 changes: 104 additions & 0 deletions ui/src/utils/lineWriter.ts
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)
}
}
}

0 comments on commit d09aa16

Please sign in to comment.