Skip to content

Commit

Permalink
feat: Add telemetry index command to list telemetry drains (#3031)
Browse files Browse the repository at this point in the history
* Add telemetry index command to list telemetry drains

* Require space or app for command
  • Loading branch information
eablack authored Oct 10, 2024
1 parent 79c17fa commit e51affb
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 0 deletions.
2 changes: 2 additions & 0 deletions cspell-dictionary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,8 @@ ossp
otherapp
otherdb
otta
otlpgrpc
otlphttp
papertrail
passw
pcxid
Expand Down
46 changes: 46 additions & 0 deletions packages/cli/src/commands/telemetry/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import {Command, flags as Flags} from '@heroku-cli/command'
import {ux} from '@oclif/core'
import {TelemetryDrains} from '../../lib/types/telemetry'

export default class Index extends Command {
static topic = 'telemetry'
static description = 'list telemetry drains'
static flags = {
space: Flags.string({char: 's', description: 'filter by space name', exactlyOne: ['app', 'space']}),
app: Flags.app({description: 'filter by app name'}),
};

public async run(): Promise<void> {
const {flags} = await this.parse(Index)
const {app, space} = flags

if (app) {
const {body: appTelemetryDrains} = await this.heroku.get<TelemetryDrains>(`/apps/${app}/telemetry-drains`, {
headers: {
Accept: 'application/vnd.heroku+json; version=3.fir',
},
})
this.display(appTelemetryDrains, 'App')
} else if (space) {
const {body: spaceTelemetryDrains} = await this.heroku.get<TelemetryDrains>(`/spaces/${space}/telemetry-drains`, {
headers: {
Accept: 'application/vnd.heroku+json; version=3.fir',
},
})
this.display(spaceTelemetryDrains, 'Space')
}
}

protected display(telemetryDrains: TelemetryDrains, ownerType: 'App' | 'Space') {
ux.styledHeader(`${ownerType} Telemetry Drains`)
ux.table(
telemetryDrains,
{
ID: {get: telemetryDrain => telemetryDrain.id},
Signals: {get: telemetryDrain => telemetryDrain.capabilities},
Endpoint: {get: telemetryDrain => telemetryDrain.exporter.endpoint},
[ownerType]: {get: telemetryDrain => telemetryDrain.owner.name},
},
)
}
}
20 changes: 20 additions & 0 deletions packages/cli/src/lib/types/telemetry.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export type TelemetryDrains = TelemetryDrain[]

export type TelemetryDrain = {
id: string;
capabilities: string[];
owner: TelemetryDrainOwner;
exporter: TelemetryExporter
}

type TelemetryDrainOwner = {
id: string;
name?: string;
type: 'app' | 'space';
}

type TelemetryExporter = {
type: 'otlphttp' | 'otlpgrpc';
endpoint: string;
headers: unknown;
}
99 changes: 99 additions & 0 deletions packages/cli/test/unit/commands/telemetry/index.unit.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import {stdout} from 'stdout-stderr'
import Cmd from '../../../../src/commands/telemetry'
import runCommand from '../../../helpers/runCommand'
import * as nock from 'nock'
import expectOutput from '../../../helpers/utils/expectOutput'
import heredoc from 'tsheredoc'
import {TelemetryDrains} from '../../../../src/lib/types/telemetry'

describe('telemetry:index', function () {
const appId = '87654321-5717-4562-b3fc-2c963f66afa6'
const spaceId = '12345678-5717-4562-b3fc-2c963f66afa6'
let appTelemetryDrains: TelemetryDrains
let spaceTelemetryDrains: TelemetryDrains

beforeEach(function () {
spaceTelemetryDrains = [
{
id: '44444321-5717-4562-b3fc-2c963f66afa6',
owner: {id: spaceId, type: 'space', name: 'myspace'},
capabilities: ['traces', 'metrics', 'logs'],
exporter: {
type: 'otlphttp',
endpoint: 'https://api.honeycomb.io/',
headers: {
'x-honeycomb-team': 'your-api-key',
'x-honeycomb-dataset': 'your-dataset',
},
},
},
]
appTelemetryDrains = [
{
id: '3fa85f64-5717-4562-b3fc-2c963f66afa6',
owner: {id: appId, type: 'app', name: 'myapp'},
capabilities: ['traces', 'metrics'],
exporter: {
type: 'otlphttp',
endpoint: 'https://api.honeycomb.io/',
headers: {
'x-honeycomb-team': 'your-api-key',
'x-honeycomb-dataset': 'your-dataset',
},
},
},
{
id: '55555f64-5717-4562-b3fc-2c963f66afa6',
owner: {id: appId, type: 'app', name: 'myapp'},
capabilities: ['logs'],
exporter: {
type: 'otlphttp',
endpoint: 'https://api.papertrail.com/',
headers: {
'x-papertrail-team': 'your-api-key',
'x-papertrail-dataset': 'your-dataset',
},
},
},
]
})

afterEach(function () {
return nock.cleanAll()
})

it('shows space telemetry drains', async function () {
nock('https://api.heroku.com', {reqheaders: {Accept: 'application/vnd.heroku+json; version=3.fir'}})
.get(`/spaces/${spaceId}/telemetry-drains`)
.reply(200, spaceTelemetryDrains)

await runCommand(Cmd, [
'--space',
spaceId,
])
expectOutput(stdout.output, heredoc(`
=== Space Telemetry Drains
Id Signals Endpoint Space
──────────────────────────────────── ─────────────────────────────── ───────────────────────── ───────
44444321-5717-4562-b3fc-2c963f66afa6 [ 'traces', 'metrics', 'logs' ] https://api.honeycomb.io/ myspace
`))
})

it('shows app telemetry drains', async function () {
nock('https://api.heroku.com', {reqheaders: {Accept: 'application/vnd.heroku+json; version=3.fir'}})
.get(`/apps/${appId}/telemetry-drains`)
.reply(200, appTelemetryDrains)

await runCommand(Cmd, [
'--app',
appId,
])
expectOutput(stdout.output, heredoc(`
=== App Telemetry Drains
Id Signals Endpoint App
──────────────────────────────────── ─────────────────────── ─────────────────────────── ─────
3fa85f64-5717-4562-b3fc-2c963f66afa6 [ 'traces', 'metrics' ] https://api.honeycomb.io/ myapp
55555f64-5717-4562-b3fc-2c963f66afa6 [ 'logs' ] https://api.papertrail.com/ myapp
`))
})
})

0 comments on commit e51affb

Please sign in to comment.