diff --git a/src/core/server/http/base_path_proxy_server.ts b/src/core/server/http/base_path_proxy_server.ts index 737aab00cff0e..d461abe54ccbd 100644 --- a/src/core/server/http/base_path_proxy_server.ts +++ b/src/core/server/http/base_path_proxy_server.ts @@ -52,6 +52,14 @@ export class BasePathProxyServer { return this.devConfig.basePathProxyTargetPort; } + public get host() { + return this.httpConfig.host; + } + + public get port() { + return this.httpConfig.port; + } + constructor( private readonly log: Logger, private readonly httpConfig: HttpConfig, @@ -92,7 +100,10 @@ export class BasePathProxyServer { await this.server.start(); this.log.info( - `basepath proxy server running at ${this.server.info.uri}${this.httpConfig.basePath}` + `basepath proxy server running at ${Url.format({ + host: this.server.info.uri, + pathname: this.httpConfig.basePath, + })}` ); } diff --git a/src/dev/cli_dev_mode/cli_dev_mode.test.ts b/src/dev/cli_dev_mode/cli_dev_mode.test.ts index b86100d161bd3..a6905df8d0c27 100644 --- a/src/dev/cli_dev_mode/cli_dev_mode.test.ts +++ b/src/dev/cli_dev_mode/cli_dev_mode.test.ts @@ -95,6 +95,7 @@ it('passes correct args to sub-classes', () => { ], "gracefulTimeout": 5000, "log": , + "mapLogLine": [Function], "script": /scripts/kibana, "watcher": Watcher { "serverShouldRestart$": [MockFunction], diff --git a/src/dev/cli_dev_mode/cli_dev_mode.ts b/src/dev/cli_dev_mode/cli_dev_mode.ts index 3cb97b08b75c2..58d5e499f189b 100644 --- a/src/dev/cli_dev_mode/cli_dev_mode.ts +++ b/src/dev/cli_dev_mode/cli_dev_mode.ts @@ -21,7 +21,7 @@ import Path from 'path'; import { REPO_ROOT } from '@kbn/dev-utils'; import * as Rx from 'rxjs'; -import { mapTo, filter, take } from 'rxjs/operators'; +import { mapTo, filter, take, tap, distinctUntilChanged, switchMap } from 'rxjs/operators'; import { CliArgs } from '../../core/server/config'; import { LegacyConfig } from '../../core/server/legacy'; @@ -142,6 +142,15 @@ export class CliDevMode { ] : []), ], + mapLogLine: (line) => { + if (!this.basePathProxy) { + return line; + } + + return line + .split(`${this.basePathProxy.host}:${this.basePathProxy.targetPort}`) + .join(`${this.basePathProxy.host}:${this.basePathProxy.port}`); + }, }); this.optimizer = new Optimizer({ @@ -168,10 +177,41 @@ export class CliDevMode { this.subscription = new Rx.Subscription(); if (basePathProxy) { - const delay$ = firstAllTrue(this.devServer.isReady$(), this.optimizer.isReady$()); + const serverReady$ = new Rx.BehaviorSubject(false); + const optimizerReady$ = new Rx.BehaviorSubject(false); + const userWaiting$ = new Rx.BehaviorSubject(false); + + this.subscription.add( + Rx.merge( + this.devServer.isReady$().pipe(tap(serverReady$)), + this.optimizer.isReady$().pipe(tap(optimizerReady$)), + userWaiting$.pipe( + distinctUntilChanged(), + switchMap((waiting) => + !waiting + ? Rx.EMPTY + : Rx.timer(1000).pipe( + tap(() => { + this.log.warn( + 'please hold', + !optimizerReady$.getValue() + ? 'optimizer is still bundling so requests have been paused' + : 'server is not ready so requests have been paused' + ); + }) + ) + ) + ) + ).subscribe(this.observer('readiness checks')) + ); basePathProxy.start({ - delayUntil: () => delay$, + delayUntil: () => { + userWaiting$.next(true); + return firstAllTrue(serverReady$, optimizerReady$).pipe( + tap(() => userWaiting$.next(false)) + ); + }, shouldRedirectFromOldBasePath, }); diff --git a/src/dev/cli_dev_mode/dev_server.ts b/src/dev/cli_dev_mode/dev_server.ts index da64c680a3c2d..f832acd38c641 100644 --- a/src/dev/cli_dev_mode/dev_server.ts +++ b/src/dev/cli_dev_mode/dev_server.ts @@ -45,6 +45,7 @@ export interface Options { processExit$?: Rx.Observable; sigint$?: Rx.Observable; sigterm$?: Rx.Observable; + mapLogLine?: DevServer['mapLogLine']; } export class DevServer { @@ -59,6 +60,7 @@ export class DevServer { private readonly script: string; private readonly argv: string[]; private readonly gracefulTimeout: number; + private readonly mapLogLine?: (line: string) => string | null; constructor(options: Options) { this.log = options.log; @@ -70,6 +72,7 @@ export class DevServer { this.processExit$ = options.processExit$ ?? Rx.fromEvent(process as EventEmitter, 'exit'); this.sigint$ = options.sigint$ ?? Rx.fromEvent(process as EventEmitter, 'SIGINT'); this.sigterm$ = options.sigterm$ ?? Rx.fromEvent(process as EventEmitter, 'SIGTERM'); + this.mapLogLine = options.mapLogLine; } isReady$() { @@ -124,8 +127,11 @@ export class DevServer { // observable which emits devServer states containing lines // logged to stdout/stderr, completes when stdio streams complete const log$ = Rx.merge(observeLines(proc.stdout!), observeLines(proc.stderr!)).pipe( - tap((line) => { - this.log.write(line); + tap((observedLine) => { + const line = this.mapLogLine ? this.mapLogLine(observedLine) : observedLine; + if (line !== null) { + this.log.write(line); + } }) );