"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.StatusService = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _rxjs = require("rxjs"); var _operators = require("rxjs/operators"); var _util = require("util"); var _routes = require("./routes"); var _status_config = require("./status_config"); var _get_summary_status = require("./get_summary_status"); var _cached_plugins_status = require("./cached_plugins_status"); var _log_overall_status = require("./log_overall_status"); /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License * 2.0 and the Server Side Public License, v 1; you may not use this file except * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ class StatusService { constructor(coreContext) { (0, _defineProperty2.default)(this, "logger", void 0); (0, _defineProperty2.default)(this, "config$", void 0); (0, _defineProperty2.default)(this, "stop$", new _rxjs.Subject()); (0, _defineProperty2.default)(this, "overall$", void 0); (0, _defineProperty2.default)(this, "pluginsStatus", void 0); (0, _defineProperty2.default)(this, "subscriptions", []); this.coreContext = coreContext; this.logger = coreContext.logger.get('status'); this.config$ = coreContext.configService.atPath(_status_config.statusConfig.path); } async preboot({ http }) { http.registerRoutes('', router => { (0, _routes.registerPrebootStatusRoute)({ router }); }); } async setup({ analytics, elasticsearch, pluginDependencies, http, metrics, savedObjects, environment, coreUsageData }) { const statusConfig = await (0, _rxjs.firstValueFrom)(this.config$); const core$ = this.setupCoreStatus({ elasticsearch, savedObjects }); this.pluginsStatus = new _cached_plugins_status.PluginsStatusService({ core$, pluginDependencies }); this.overall$ = (0, _rxjs.combineLatest)([core$, this.pluginsStatus.getAll$()]).pipe( // Prevent many emissions at once from dependency status resolution from making this too noisy (0, _operators.debounceTime)(80), (0, _operators.map)(([coreStatus, pluginsStatus]) => { const summary = (0, _get_summary_status.getSummaryStatus)([...Object.entries(coreStatus), ...Object.entries(pluginsStatus)]); this.logger.debug(`Recalculated overall status`, { kibana: { status: summary } }); return summary; }), (0, _operators.distinctUntilChanged)(_util.isDeepStrictEqual), (0, _operators.shareReplay)(1)); this.setupAnalyticsContextAndEvents(analytics); const coreOverall$ = core$.pipe( // Prevent many emissions at once from dependency status resolution from making this too noisy (0, _operators.debounceTime)(25), (0, _operators.map)(coreStatus => { const coreOverall = (0, _get_summary_status.getSummaryStatus)([...Object.entries(coreStatus)]); this.logger.debug(`Recalculated core overall status`, { kibana: { status: coreOverall } }); return coreOverall; }), (0, _operators.distinctUntilChanged)(_util.isDeepStrictEqual), (0, _operators.shareReplay)(1)); // Create unused subscriptions to ensure all underlying lazy observables are started. this.subscriptions.push(this.overall$.subscribe(), coreOverall$.subscribe()); const commonRouteDeps = { config: { allowAnonymous: statusConfig.allowAnonymous, packageInfo: this.coreContext.env.packageInfo, serverName: http.getServerInfo().name, uuid: environment.instanceUuid }, metrics, status: { overall$: this.overall$, plugins$: this.pluginsStatus.getAll$(), core$, coreOverall$ }, incrementUsageCounter: coreUsageData.incrementUsageCounter }; const router = http.createRouter(''); (0, _routes.registerStatusRoute)({ router, ...commonRouteDeps }); return { core$, coreOverall$, overall$: this.overall$, plugins: { set: this.pluginsStatus.set.bind(this.pluginsStatus), getDependenciesStatus$: this.pluginsStatus.getDependenciesStatus$.bind(this.pluginsStatus), getDerivedStatus$: this.pluginsStatus.getDerivedStatus$.bind(this.pluginsStatus) }, isStatusPageAnonymous: () => statusConfig.allowAnonymous }; } start() { if (!this.pluginsStatus || !this.overall$) { throw new Error(`StatusService#setup must be called before #start`); } this.pluginsStatus.blockNewRegistrations(); (0, _log_overall_status.getOverallStatusChanges)(this.overall$, this.stop$).subscribe(message => { this.logger.info(message); }); } stop() { var _this$pluginsStatus; this.stop$.next(); this.stop$.complete(); this.subscriptions.forEach(subscription => { subscription.unsubscribe(); }); (_this$pluginsStatus = this.pluginsStatus) === null || _this$pluginsStatus === void 0 ? void 0 : _this$pluginsStatus.stop(); this.subscriptions = []; } setupCoreStatus({ elasticsearch, savedObjects }) { return (0, _rxjs.combineLatest)([elasticsearch.status$, savedObjects.status$]).pipe((0, _operators.map)(([elasticsearchStatus, savedObjectsStatus]) => ({ elasticsearch: elasticsearchStatus, savedObjects: savedObjectsStatus })), (0, _operators.distinctUntilChanged)(_util.isDeepStrictEqual), (0, _operators.shareReplay)(1)); } setupAnalyticsContextAndEvents(analytics) { // Set an initial "initializing" status, so we can attach it to early events. const context$ = new _rxjs.BehaviorSubject({ overall_status_level: 'initializing', overall_status_summary: 'Kibana is starting up' }); // The schema is the same for the context and the events. const schema = { overall_status_level: { type: 'keyword', _meta: { description: 'The current availability level of the service.' } }, overall_status_summary: { type: 'text', _meta: { description: 'A high-level summary of the service status.' } } }; const overallStatusChangedEventName = 'core-overall_status_changed'; analytics.registerEventType({ eventType: overallStatusChangedEventName, schema }); analytics.registerContextProvider({ name: 'status info', context$, schema }); this.overall$.pipe((0, _operators.takeUntil)(this.stop$), (0, _operators.map)(({ level, summary }) => ({ overall_status_level: level.toString(), overall_status_summary: summary })), // Emit the event before spreading the status to the context. // This way we see from the context the previous status and the current one. (0, _rxjs.tap)(statusPayload => analytics.reportEvent(overallStatusChangedEventName, statusPayload))).subscribe(context$); } } exports.StatusService = StatusService;