UNPKG

3.76 kBJavaScriptView Raw
1'use strict'
2
3const cli = require('heroku-cli-util')
4const { capitalize } = require('lodash')
5const PGDIAGNOSE_HOST = process.env.PGDIAGNOSE_URL || 'https://pgdiagnose.herokai.com'
6
7async function run(context, heroku) {
8 const fetcher = require('../lib/fetcher')(heroku)
9 const host = require('../lib/host')
10 const util = require('../lib/util')
11 const URL = require('url')
12 const uuid = require('uuid')
13
14 const { app, args, flags } = context
15
16 let generateParams = async function (url, db, dbName) {
17 let base_params = {
18 url: URL.format(url),
19 plan: db.plan.name.split(':')[1],
20 app: db.app.name,
21 database: dbName,
22 }
23
24 if (!util.starterPlan(db)) {
25 base_params.metrics = await heroku.get(`/client/v11/databases/${db.id}/metrics`, { host: host(db) })
26 let burstData = await heroku.get(`/client/v11/databases/${db.id}/burst_status`, { host: host(db) })
27 if (burstData && Object.keys(burstData).length !== 0) {
28 base_params.burst_data_present = true
29 base_params.burst_status = burstData.burst_status
30 }
31 }
32
33 return base_params
34 }
35
36 let generateReport = async function (database) {
37 let attachment = await fetcher.attachment(app, database)
38 const { addon: db } = attachment
39 let config = await heroku.get(`/apps/${app}/config-vars`)
40
41 const { url } = util.getConnectionDetails(attachment, config)
42 const dbName = util.getConfigVarNameFromAttachment(attachment, config)
43
44 let params = await generateParams(url, db, dbName)
45 return await heroku.post('/reports', {
46 host: PGDIAGNOSE_HOST,
47 body: params,
48 });
49 }
50
51 let displayReport = (report) => {
52 if (flags.json) {
53 cli.styledJSON(report)
54 return
55 }
56
57 cli.log(`Report ${report.id} for ${report.app}::${report.database}
58available for one month after creation on ${report.created_at}
59`)
60 let display = (checks) => {
61 checks.forEach((check) => {
62 let color = cli.color[check.status] || ((txt) => txt)
63 cli.log(color(`${check.status.toUpperCase()}: ${check.name}`))
64
65 if (check.status === 'green') return
66 if (!check.results) return
67
68 if (Array.isArray(check.results)) {
69 if (!check.results.length) return
70
71 let keys = Object.keys(check.results[0])
72 cli.table(check.results, {
73 columns: keys.map((key) => ({ label: capitalize(key), key: key })),
74 })
75 } else {
76 if (!Object.keys(check.results).length) return
77
78 let key = Object.keys(check.results)[0]
79 cli.log(
80 `${key
81 .split('_')
82 .map((s) => capitalize(s))
83 .join(' ')} ${check.results[key]}`,
84 )
85 }
86 })
87 }
88 display(report.checks.filter((c) => c.status === 'red'))
89 display(report.checks.filter((c) => c.status === 'yellow'))
90 display(report.checks.filter((c) => c.status === 'green'))
91 display(report.checks.filter((c) => !['red', 'yellow', 'green'].find((d) => d === c.status)))
92 }
93
94 let report
95 let id = args['DATABASE|REPORT_ID']
96 if (id && uuid.validate(id)) {
97 report = await heroku.get(`/reports/${encodeURIComponent(id)}`, { host: PGDIAGNOSE_HOST })
98 } else {
99 report = await generateReport(id)
100 }
101
102 displayReport(report)
103}
104
105module.exports = {
106 topic: 'pg',
107 command: 'diagnose',
108 description: 'run or view diagnostics report',
109 help: `
110defaults to DATABASE_URL database if no DATABASE is specified
111if REPORT_ID is specified instead, a previous report is displayed
112`,
113 needsApp: true,
114 needsAuth: true,
115 args: [{ name: 'DATABASE|REPORT_ID', optional: true }],
116 flags: [{ name: 'json', description: "format output as JSON", hasValue: false }],
117 run: cli.command({ preauth: true }, run),
118}