1 | 'use strict'
|
2 |
|
3 | let cli = require('heroku-cli-util')
|
4 | let EventSource = require('@heroku/eventsource')
|
5 | let url = require('url')
|
6 | let liner = require('../lib/line_transform')
|
7 | const colorize = require('./colorize')
|
8 | const HTTP = require('http-call')
|
9 |
|
10 | function readLogs (logplexURL) {
|
11 | let u = url.parse(logplexURL)
|
12 | if (u.query && u.query.includes('srv')) {
|
13 | return readLogsV1(logplexURL)
|
14 | } else {
|
15 | return readLogsV2(logplexURL)
|
16 | }
|
17 | }
|
18 |
|
19 | async function readLogsV1 (logplexURL) {
|
20 | let {response} = await HTTP.stream(logplexURL)
|
21 | return new Promise(function (resolve, reject) {
|
22 | response.setEncoding('utf8')
|
23 | liner.setEncoding('utf8')
|
24 | response.pipe(liner)
|
25 | liner.on('data', line => cli.log(colorize(line)))
|
26 | response.on('end', resolve)
|
27 | response.on('error', reject)
|
28 | })
|
29 | }
|
30 |
|
31 | function readLogsV2 (logplexURL) {
|
32 | return new Promise(function (resolve, reject) {
|
33 | const u = url.parse(logplexURL, true)
|
34 | const isTail = u.query.tail && u.query.tail === 'true'
|
35 | const userAgent = process.env.HEROKU_DEBUG_USER_AGENT || 'heroku-run'
|
36 | const proxy = process.env.https_proxy || process.env.HTTPS_PROXY
|
37 | const es = new EventSource(logplexURL, {
|
38 | proxy,
|
39 | headers: {
|
40 | 'User-Agent': userAgent
|
41 | }
|
42 | })
|
43 |
|
44 | es.onerror = function (err) {
|
45 | if (err && (err.status || err.message)) {
|
46 | const msg = (isTail && (err.status === 404 || err.status === 403)) ?
|
47 | 'Log stream timed out. Please try again.' :
|
48 | `Logs eventsource failed with: ${err.status} ${err.message}`
|
49 | reject(msg)
|
50 | es.close()
|
51 | }
|
52 |
|
53 | if (!isTail) {
|
54 | resolve()
|
55 | es.close()
|
56 | }
|
57 |
|
58 |
|
59 | }
|
60 |
|
61 | es.onmessage = function (e) {
|
62 | e.data.trim().split(/\n+/).forEach((line) => {
|
63 | cli.log(colorize(line))
|
64 | })
|
65 | }
|
66 | })
|
67 | }
|
68 |
|
69 | async function logDisplayer (heroku, options) {
|
70 | process.stdout.on('error', err => {
|
71 | if (err.code === 'EPIPE') {
|
72 | process.exit(0)
|
73 | } else {
|
74 | console.error(err.stack)
|
75 | process.exit(1)
|
76 | }
|
77 | })
|
78 | const response = await heroku.request({
|
79 | path: `/apps/${options.app}/log-sessions`,
|
80 | method: 'POST',
|
81 | body: {
|
82 | tail: options.tail,
|
83 | dyno: options.dyno,
|
84 | source: options.source,
|
85 | lines: options.lines
|
86 | }
|
87 | })
|
88 | return readLogs(response.logplex_url)
|
89 | }
|
90 |
|
91 | module.exports = logDisplayer
|