Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add telemetry #1166

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .rpsrc
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@
"consul_enabled": false,
"consul_host": "localhost",
"consul_port": "8500",
"consul_key_prefix": "RPS"
"consul_key_prefix": "RPS",
"telegraf_host":"localhost",
"telegraf_port": 8020
}
86 changes: 86 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"express-validator": "^7.0.1",
"express-ws": "^5.0.2",
"got": "^11.8.6",
"hot-shots": "^10.0.0",
"http-z": "^6.1.2",
"minimist": "^1.2.8",
"mqtt": "^5.1.2",
Expand Down
6 changes: 5 additions & 1 deletion src/Index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import * as ServiceManager from './serviceManager'
import { ConsulService } from './consul'
import { type IServiceManager } from './interfaces/IServiceManager'
import path = require('path')
import expressStatsdInit from './middleware/stats'
import statsD from './utils/stats'

const log = new Logger('Index')

Expand All @@ -42,11 +44,12 @@ config.delay_tls_put_data_sync = 5000
log.silly(`config: ${JSON.stringify(config, null, 2)}`)

Environment.Config = config

statsD.Initialize()
const app = express()
app.use(cors())
app.use(express.urlencoded())
app.use(express.json())
app.use(expressStatsdInit())

export const waitForDB = async function (db: IDB): Promise<void> {
await backOff(async () => await db.query('SELECT 1'), {
Expand All @@ -67,6 +70,7 @@ export const waitForSecretsManager = async function (secretsManager: ISecretMana
}

export const startItUp = (): void => {
statsD.increment('startup')
const configurator = new Configurator()
log.silly(`WebSocket Cert Info ${JSON.stringify(Environment.Config)}`)
const serverForEnterpriseAssistant: WSEnterpriseAssistantListener = new WSEnterpriseAssistantListener(new Logger('WSEnterpriseAssistantListener'))
Expand Down
42 changes: 42 additions & 0 deletions src/middleware/stats.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*********************************************************************
* Copyright (c) Intel Corporation 2022
* SPDX-License-Identifier: Apache-2.0
**********************************************************************/

import { type Handler } from 'express'
import statsD from '../utils/stats'

export default function expressStatsdInit (): Handler {
const client = statsD

return function expressStatsd (req, res, next) {
const startTime = new Date().getTime()

// Function called on response finish that sends stats to statsd
function sendStats (): void {
// Status Code
const statusCode: string = res.statusCode.toString() || 'unknown_status'
const duration = new Date().getTime() - startTime
client.increment('request', { statusCode, method: req.method, url: req.baseUrl, duration: duration.toString() })
client.timing('response_time', duration)

cleanup()
}

// Function to clean up the listeners we've added
function cleanup (): void {
res.removeListener('finish', sendStats)
res.removeListener('error', cleanup)
res.removeListener('close', cleanup)
}

// Add response listeners
res.once('finish', sendStats)
res.once('error', cleanup)
res.once('close', cleanup)

if (next) {
next()
}
}
}
2 changes: 2 additions & 0 deletions src/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ export interface RPSConfig {
disable_cira_domain_name?: string
jwt_token_header: string
jwt_tenant_property: string
telegraf_host: string
telegraf_port: number
}
export enum AMTRedirectionServiceEnabledStates {
DISABLED = 32768,
Expand Down
3 changes: 3 additions & 0 deletions src/stateMachines/activation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import ClientResponseMsg from '../utils/ClientResponseMsg'
import { Unconfiguration } from './unconfiguration'
import { type DeviceCredentials } from '../interfaces/ISecretManagerService'
import { NetworkConfiguration } from './networkConfiguration'
import statsD from '../utils/stats'

export interface ActivationContext {
profile: AMTConfiguration
Expand Down Expand Up @@ -783,9 +784,11 @@ export class Activation {
let method = null
if (status === 'success') {
method = 'success'
statsD.increment('activation.success')
} else if (status === 'error') {
clientObj.status.Status = context.errorMessage !== '' ? context.errorMessage : 'Failed'
method = 'failed'
statsD.increment('activation.failure')
}
const responseMessage = ClientResponseMsg.get(clientId, null, status, method, JSON.stringify(clientObj.status))
this.logger.info(JSON.stringify(responseMessage, null, '\t'))
Expand Down
6 changes: 6 additions & 0 deletions src/stateMachines/unconfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { type AMTConfiguration } from '../models'
import { Error } from './error'
import { invokeWsmanCall } from './common'
import { Environment } from '../utils/Environment'
import statsD from '../utils/stats'

export interface UnconfigContext {
clientId: string
Expand Down Expand Up @@ -607,6 +608,7 @@ export class Unconfiguration {
type: 'final'
},
SUCCESS: {
entry: ['Metric Capture'],
type: 'final'
}
}
Expand Down Expand Up @@ -634,6 +636,9 @@ export class Unconfiguration {
shouldRetry: (context, event) => context.retryCount < 3 && event.data instanceof UNEXPECTED_PARSE_ERROR
},
actions: {
'Metric Capture': (context, event) => {
statsD.increment('unconfiguration.success')
},
'Update CIRA Status': (context, event) => {
devices[context.clientId].status.CIRAConnection = context.statusMessage
},
Expand All @@ -644,6 +649,7 @@ export class Unconfiguration {
devices[context.clientId].status.TLSConfiguration = ''
devices[context.clientId].status.CIRAConnection = ''
devices[context.clientId].status.Status = context.statusMessage
statsD.increment('unconfiguration.failure')
},
'Reset Unauth Count': (context, event) => { devices[context.clientId].unauthCount = 0 },
'Read WiFi Endpoint Settings Pull Response': this.readWiFiEndpointSettingsPullResponse.bind(this),
Expand Down
4 changes: 3 additions & 1 deletion src/test/helper/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,7 @@ export const config: RPSConfig = {
db_provider: 'postgres',
connection_string: 'postgresql://postgresadmin:admin123@localhost:5432/rpsdb',
jwt_tenant_property: '',
jwt_token_header: ''
jwt_token_header: '',
telegraf_host: 'localhost',
telegraf_port: 8020
}
61 changes: 61 additions & 0 deletions src/utils/stats.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*********************************************************************
* Copyright (c) Intel Corporation 2022
* SPDX-License-Identifier: Apache-2.0
**********************************************************************/

import { StatsD } from 'hot-shots'
import { Environment } from './Environment'

class StatsDClient {
private static instance: StatsDClient
private client: StatsD

private constructor () {

}

public static getInstance (): StatsDClient {
if (!StatsDClient.instance) {
StatsDClient.instance = new StatsDClient()
}

return StatsDClient.instance
}

public Initialize (): void {
this.client = new StatsD({
host: Environment.Config.telegraf_host,
port: Environment.Config.telegraf_port,
globalTags: { service: 'rps' },
errorHandler: this.errorHandler
})
}

private errorHandler (error: Error): void {
console.error('Error encountered in StatsD client:', error)
}

public increment (stat: string, tags?: string[] | Record<string, string>): void {
this.client.increment('rps.' + stat, tags)

Check failure on line 39 in src/utils/stats.ts

View workflow job for this annotation

GitHub Actions / JEST Tests

Activation State Machine ► Activation State Machine test state machine should send success message to device ► Activation State Machine test state machine should send success message to device

Failed test found in: junit.xml Error: TypeError: Cannot read properties of undefined (reading 'increment')
Raw output
TypeError: Cannot read properties of undefined (reading 'increment')
    at StatsDClient.increment (/home/runner/work/rps/rps/src/utils/stats.ts:39:17)
    at Activation.sendMessageToDevice (/home/runner/work/rps/rps/src/stateMachines/activation.ts:787:14)
    at Object.<anonymous> (/home/runner/work/rps/rps/src/stateMachines/activation.test.ts:1276:18)
    at Promise.then.completed (/home/runner/work/rps/rps/node_modules/jest-circus/build/utils.js:391:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/home/runner/work/rps/rps/node_modules/jest-circus/build/utils.js:316:10)
    at _callCircusTest (/home/runner/work/rps/rps/node_modules/jest-circus/build/run.js:218:40)
    at _runTest (/home/runner/work/rps/rps/node_modules/jest-circus/build/run.js:155:3)
    at _runTestsForDescribeBlock (/home/runner/work/rps/rps/node_modules/jest-circus/build/run.js:66:9)
    at _runTestsForDescribeBlock (/home/runner/work/rps/rps/node_modules/jest-circus/build/run.js:60:9)

Check failure on line 39 in src/utils/stats.ts

View workflow job for this annotation

GitHub Actions / JEST Tests

Activation State Machine ► Activation State Machine test state machine should send error message to device ► Activation State Machine test state machine should send error message to device

Failed test found in: junit.xml Error: TypeError: Cannot read properties of undefined (reading 'increment')
Raw output
TypeError: Cannot read properties of undefined (reading 'increment')
    at StatsDClient.increment (/home/runner/work/rps/rps/src/utils/stats.ts:39:17)
    at Activation.sendMessageToDevice (/home/runner/work/rps/rps/src/stateMachines/activation.ts:791:14)
    at Object.<anonymous> (/home/runner/work/rps/rps/src/stateMachines/activation.test.ts:1287:18)
    at Promise.then.completed (/home/runner/work/rps/rps/node_modules/jest-circus/build/utils.js:391:28)
    at new Promise (<anonymous>)
    at callAsyncCircusFn (/home/runner/work/rps/rps/node_modules/jest-circus/build/utils.js:316:10)
    at _callCircusTest (/home/runner/work/rps/rps/node_modules/jest-circus/build/run.js:218:40)
    at _runTest (/home/runner/work/rps/rps/node_modules/jest-circus/build/run.js:155:3)
    at _runTestsForDescribeBlock (/home/runner/work/rps/rps/node_modules/jest-circus/build/run.js:66:9)
    at _runTestsForDescribeBlock (/home/runner/work/rps/rps/node_modules/jest-circus/build/run.js:60:9)

Check failure on line 39 in src/utils/stats.ts

View workflow job for this annotation

GitHub Actions / JEST Tests

Unconfiguration State Machine ► Unconfiguration State Machine should eventually reach "SUCCESS" ► Unconfiguration State Machine should eventually reach "SUCCESS"

Failed test found in: junit.xml Error: TypeError: Cannot read properties of undefined (reading 'increment')
Raw output
TypeError: Cannot read properties of undefined (reading 'increment')
    at StatsDClient.increment (/home/runner/work/rps/rps/src/utils/stats.ts:39:17)
    at Metric Capture (/home/runner/work/rps/rps/src/stateMachines/unconfiguration.ts:640:18)
    at Interpreter._exec (/home/runner/work/rps/rps/node_modules/xstate/lib/interpreter.js:171:18)
    at handleAction (/home/runner/work/rps/rps/node_modules/xstate/lib/actions.js:596:11)
    at processBlock (/home/runner/work/rps/rps/node_modules/xstate/lib/actions.js:627:24)
    at Array.map (<anonymous>)
    at Object.resolveActions (/home/runner/work/rps/rps/node_modules/xstate/lib/actions.js:652:52)
    at StateNode.resolveTransition (/home/runner/work/rps/rps/node_modules/xstate/lib/StateNode.js:917:36)
    at StateNode.transition (/home/runner/work/rps/rps/node_modules/xstate/lib/StateNode.js:840:17)
    at /home/runner/work/rps/rps/node_modules/xstate/lib/interpreter.js:956:28
}

public decrement (stat: string, tags?: string[], sampleRate?: number): void {
this.client.decrement('rps.' + stat, 1, sampleRate, tags)
}

public timing (stat: string, value: number): void {
this.client.timing('rps.' + stat, value)
}

public event (title: string, text?: string, options?: any, tags?: string[]): void {
this.client.event(title, text, options, tags)
}

public close (callback?: (error?: Error) => void): void {
this.client.close(callback)
}
}

// Export the singleton instance
const statsD = StatsDClient.getInstance()
export default statsD
Loading