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

Prometheus metrics reporting #258

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
21 changes: 21 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 @@ -38,6 +38,7 @@
"minimatch": "^3.0.4",
"probot": "^7.4.0",
"probot-config": "^1.0.1",
"prom-client": "^11.3.0",
"raven": "^2.6.4"
},
"devDependencies": {
Expand Down
20 changes: 19 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,25 @@ import { WorkerContext } from './models'
import Raven from 'raven'
import { RepositoryWorkers } from './repository-workers'
import sentryStream from 'bunyan-sentry-stream'
import { Headers } from 'probot/lib/github'
import { RepositoryReference, PullRequestReference } from './github-models'
import myAppId from './myappid'
import { metricsReporter } from './metrics'

async function getWorkerContext (options: {app: Application, context: Context, installationId: number}): Promise<WorkerContext> {
const { app, context, installationId } = options
const config = await loadConfig(context)
const log = app.log
const createGitHubAPI = async () => {
return app.auth(installationId, log)
const github = await app.auth(installationId, log)
const { owner, repo } = options.context.repo()
github.hook.after('request', (response, requestOptions) => {
const responseHeaders = response.headers as Headers
const rateLimit = Number(responseHeaders['x-ratelimit-remaining'])
const apiVersion = requestOptions.query ? 'v4' : 'v3'
metricsReporter.rateLimitGauge.set({ owner, repo, apiVersion }, rateLimit)
})
return github
}
return {
createGitHubAPI,
Expand Down Expand Up @@ -90,6 +100,14 @@ export = (app: Application) => {
})
}

// Get an express router to expose new HTTP endpoints
const router = app.route('/')

// Add a new route
router.get('/metrics', (req: any, res: any) => {
res.send(metricsReporter.outputMetrics())
})

app.on([
'pull_request.opened',
'pull_request.edited',
Expand Down
44 changes: 44 additions & 0 deletions src/metrics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import promClient, { Gauge, labelValues } from 'prom-client'

const makeMockGauge = (name: String): Partial<Gauge> => ({
set: (labels: labelValues | number, value: number) => {} // tslint:disable-line:no-empty
})

class MetricsReporter {
public rateLimitGauge: Gauge
public queueSizeGauge: Gauge

constructor (public enabled: boolean) {
this.enabled = enabled

if (this.enabled) {
promClient.collectDefaultMetrics()

this.rateLimitGauge = new promClient.Gauge({
name: 'probot_auto_merge_github_rate_limit_remaining',
help:
'Github rate limit as reported by the `x-ratelimit-remaining` header',
labelNames: ['owner', 'repo', 'apiVersion']
})

this.queueSizeGauge = new promClient.Gauge({
name: 'probot_auto_merge_pr_queue_size',
help: 'Number of PRs in the Probot Auto Merge queue',
labelNames: ['owner', 'repo']
})
} else {
this.rateLimitGauge = makeMockGauge('rate limit') as Gauge
this.queueSizeGauge = makeMockGauge('queue size') as Gauge
}
}

outputMetrics (): string {
return this.enabled ? promClient.register.metrics() : 'nothing'
}
}

const metricsReporter = new MetricsReporter(
process.env.NODE_ENV === 'production'
)

export { metricsReporter }
21 changes: 20 additions & 1 deletion src/repository-worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import { WaitQueue } from './WaitQueue'
import { RepositoryReference, PullRequestReference } from './github-models'
import { handlePullRequest, PullRequestContext } from './pull-request-handler'
import { WorkerContext } from './models'
import { metricsReporter } from './metrics'

export class RepositoryWorker {
private waitQueue: WaitQueue<number>
private context: WorkerContext
public sendMetricsInterval?: NodeJS.Timeout

constructor (
public repository: RepositoryReference,
Expand All @@ -17,7 +19,24 @@ export class RepositoryWorker {
this.waitQueue = new WaitQueue<number>(
(pullRequestNumber: number) => `${pullRequestNumber}`,
this.handlePullRequestNumber.bind(this),
onDrain
() => {
this.sendMetricsInterval && clearInterval(this.sendMetricsInterval)
this.sendQueueSizeMetrics()
onDrain()
}
)

metricsReporter.enabled &&
(this.sendMetricsInterval = setInterval(
this.sendQueueSizeMetrics.bind(this),
1000
))
}

private sendQueueSizeMetrics (): void {
metricsReporter.queueSizeGauge.set(
{ owner: this.repository.owner, repo: this.repository.repo },
this.waitQueue.getQueuedTasks().length
)
}

Expand Down
10 changes: 9 additions & 1 deletion test/mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,15 @@ export function createPullRequestInfo (pullRequestInfo?: Partial<PullRequestInfo

export function createGithubApi (options?: DeepPartial<GitHubAPI>): GitHubAPI {
return {
...options
...options,
hook: {
before: (when: string, cb: () => void) => {
return
},
after: (when: string, cb: () => void) => {
return
}
}
} as GitHubAPI
}

Expand Down