Skip to content
Merged
10 changes: 7 additions & 3 deletions docs/reference/user-activity.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ User activity events are written as JSON log entries. When using the JSON loggin

### Service fields

| **Field** | **Description** |
| --- | --- |
| `service.version` | Version of Kibana that emitted the event. |
| **Field** | **Description** |
|----------------------|------------------------------------------------|
| `service.id` | The cluster ID. |
| `service.node.roles` | Roles of Kibana: `["ui", "background_tasks"]`. |
| `service.state` | The status of Kibana. |
| `service.type` | `kibana`. |
| `service.version` | Version of Kibana that emitted the event. |
1 change: 1 addition & 0 deletions src/core/packages/elasticsearch/server-internal/moon.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ dependsOn:
- '@kbn/core-http-server-mocks'
- '@kbn/core-security-server-internal'
- '@kbn/core-security-server-mocks'
- '@kbn/core-logging-server-internal'
tags:
- shared-server
- package
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ beforeEach(() => {
http: httpServiceMock.createInternalSetupContract(),
executionContext: executionContextServiceMock.createInternalSetupContract(),
security: securityServiceMock.createInternalSetup(),
loggingSystem: loggingSystemMock.create(),
};

env = Env.createDefault(REPO_ROOT, getEnvOptions());
Expand Down Expand Up @@ -103,7 +104,7 @@ beforeEach(() => {

isScriptingEnabledMock.mockResolvedValue(true);

getClusterInfoMock.mockReturnValue(of({}));
getClusterInfoMock.mockReturnValue(of({ cluster_uuid: 'test-cluster-uuid' }));

// @ts-expect-error TS does not get that `pollEsNodesVersion` is mocked
pollEsNodesVersionMocked.mockImplementation(pollEsNodesVersionActual);
Expand Down Expand Up @@ -268,6 +269,16 @@ describe('#setup', () => {

expect(mockedClient.nodes.info).toHaveBeenCalledTimes(2);
});

it("should inject the cluster's ID in the logging system", async () => {
const setupContract = await elasticsearchService.setup(setupDeps);

await firstValueFrom(setupContract.clusterInfo$);

expect(setupDeps.loggingSystem.setGlobalContext).toHaveBeenCalledWith({
service: { id: 'test-cluster-uuid' },
});
});
});

describe('#start', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
} from '@kbn/core-elasticsearch-client-server-internal';

import type { InternalSecurityServiceSetup } from '@kbn/core-security-server-internal';
import type { ILoggingSystem } from '@kbn/core-logging-server-internal';
import { registerAnalyticsContextProvider } from './register_analytics_context_provider';
import type { ElasticsearchConfigType } from './elasticsearch_config';
import { ElasticsearchConfig } from './elasticsearch_config';
Expand All @@ -54,6 +55,7 @@ export interface SetupDeps {
http: InternalHttpServiceSetup;
executionContext: InternalExecutionContextSetup;
security: InternalSecurityServiceSetup;
loggingSystem: Pick<ILoggingSystem, 'setGlobalContext'>;
}

/** @internal */
Expand Down Expand Up @@ -145,6 +147,9 @@ export class ElasticsearchService
this.esNodesCompatibility$ = esNodesCompatibility$;

this.clusterInfo$ = getClusterInfo$(this.client.asInternalUser).pipe(takeUntil(this.stop$));
this.clusterInfo$.subscribe(({ cluster_uuid }) =>
deps.loggingSystem.setGlobalContext({ service: { id: cluster_uuid } })
);
registerAnalyticsContextProvider(deps.analytics, this.clusterInfo$);

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"@kbn/core-http-server-mocks",
"@kbn/core-security-server-internal",
"@kbn/core-security-server-mocks",
"@kbn/core-logging-server-internal",
],
"exclude": [
"target/**/*",
Expand Down
8 changes: 6 additions & 2 deletions src/core/packages/root/server-internal/src/server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ test('sets service.version global context to kibana version on traditional', ()
expect(traditionalEnv.packageInfo.buildFlavor).toBe('traditional');
expect(loggingSystem.setGlobalContext).toHaveBeenCalledTimes(1);
expect(loggingSystem.setGlobalContext).toHaveBeenCalledWith({
service: { version: traditionalEnv.packageInfo.version },
service: { state: 'initializing', type: 'kibana', version: traditionalEnv.packageInfo.version },
});
});

Expand All @@ -107,7 +107,11 @@ test('sets service.version global context to build sha short on serverless', ()
expect(serverlessEnv.packageInfo.buildFlavor).toBe('serverless');
expect(loggingSystem.setGlobalContext).toHaveBeenCalledTimes(1);
expect(loggingSystem.setGlobalContext).toHaveBeenCalledWith({
service: { version: serverlessEnv.packageInfo.buildShaShort },
service: {
state: 'initializing',
type: 'kibana',
version: serverlessEnv.packageInfo.buildShaShort,
},
});
});

Expand Down
6 changes: 5 additions & 1 deletion src/core/packages/root/server-internal/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,9 @@ export class Server {
env.packageInfo.buildFlavor === 'serverless'
? env.packageInfo.buildShaShort
: env.packageInfo.version;
this.loggingSystem.setGlobalContext({ service: { version: serviceVersion } });
this.loggingSystem.setGlobalContext({
service: { version: serviceVersion, type: 'kibana', state: 'initializing' },
});
this.logger = this.loggingSystem.asLoggerFactory();
this.log = this.logger.get('server');
this.configService = new ConfigService(rawConfigProvider, env, this.logger);
Expand Down Expand Up @@ -322,6 +324,7 @@ export class Server {
http: httpSetup,
executionContext: executionContextSetup,
security: securitySetup,
loggingSystem: this.loggingSystem,
});

const dataStreamsSetup = await this.dataStreams.setup();
Expand Down Expand Up @@ -373,6 +376,7 @@ export class Server {
httpRateLimiter: httpRateLimiterSetup,
metrics: metricsSetup,
coreUsageData: coreUsageDataSetup,
loggingSystem: this.loggingSystem,
});

const customBrandingSetup = this.customBranding.setup();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ describe('StatusService', () => {
},
metrics: metricsServiceMock.createInternalSetupContract(),
coreUsageData: coreUsageDataServiceMock.createSetupContract(),
loggingSystem: loggingSystemMock.create(),
...overrides,
};
};
Expand Down Expand Up @@ -622,6 +623,17 @@ describe('StatusService', () => {
`);
});
});

describe('logging service.state extension', () => {
it('should extend the logging service.state global info once it resolves a status', async () => {
const deps = setupDeps();
const setupContract = await service.setup(deps);
await firstValueFrom(setupContract.overall$);
expect(deps.loggingSystem.setGlobalContext).toHaveBeenCalledWith({
service: { state: 'available' },
});
});
});
});

describe('#start', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import type { InternalMetricsServiceSetup } from '@kbn/core-metrics-server-inter
import type { InternalSavedObjectsServiceSetup } from '@kbn/core-saved-objects-server-internal';
import type { InternalCoreUsageDataSetup } from '@kbn/core-usage-data-base-server-internal';
import { type ServiceStatus, type CoreStatus } from '@kbn/core-status-common';
import type { ILoggingSystem } from '@kbn/core-logging-server-internal';
import { registerStatusRoute, registerPrebootStatusRoute } from './routes';

import { statusConfig as config, type StatusConfigType } from './status_config';
Expand Down Expand Up @@ -69,6 +70,7 @@ export interface StatusServiceSetupDeps {
metrics: InternalMetricsServiceSetup;
savedObjects: Pick<InternalSavedObjectsServiceSetup, 'status$'>;
coreUsageData: Pick<InternalCoreUsageDataSetup, 'incrementUsageCounter'>;
loggingSystem: Pick<ILoggingSystem, 'setGlobalContext'>;
}

export class StatusService implements CoreService<InternalStatusServiceSetup> {
Expand Down Expand Up @@ -102,6 +104,7 @@ export class StatusService implements CoreService<InternalStatusServiceSetup> {
savedObjects,
environment,
coreUsageData,
loggingSystem,
}: StatusServiceSetupDeps) {
const statusConfig = await firstValueFrom(this.config$);
const core$ = (this.core$ = this.setupCoreStatus({
Expand All @@ -121,6 +124,8 @@ export class StatusService implements CoreService<InternalStatusServiceSetup> {
status: summary,
},
});
// Changing the state after the log above so that we can see the previous state before recalculating the status.
loggingSystem.setGlobalContext({ service: { state: summary.level.toString() } });
return summary;
}),
distinctUntilChanged<ServiceStatus<unknown>>(isDeepStrictEqual),
Expand Down
Loading