Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove non-essential ES-client stats from /api/stats #145120

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ describe('getAgentsSocketsStats()', () => {
},
});

const agent2 = getHttpAgentMock({
const agent2 = getHttpsAgentMock({
sockets: {
node1: [mockSocket, mockSocket, mockSocket],
node4: [mockSocket],
Expand All @@ -47,101 +47,9 @@ describe('getAgentsSocketsStats()', () => {

const stats = getAgentsSocketsStats(new Set<Agent>([agent1, agent2]));
expect(stats).toEqual({
averageActiveSocketsPerNode: 2.6666666666666665,
averageIdleSocketsPerNode: 4.5,
connectedNodes: 4,
mostActiveNodeSockets: 6,
mostIdleNodeSockets: 8,
nodesWithActiveSockets: 3,
nodesWithIdleSockets: 2,
protocol: 'http',
totalActiveSockets: 8,
totalIdleSockets: 9,
totalQueuedRequests: 6,
});
});

it('takes into account Agent types to determine the `protocol`', () => {
const httpAgent = getHttpAgentMock({
sockets: { node1: [mockSocket] },
freeSockets: {},
requests: {},
});

const httpsAgent = getHttpsAgentMock({
sockets: { node1: [mockSocket] },
freeSockets: {},
requests: {},
});

const noAgents = new Set<Agent>();
const httpAgents = new Set<Agent>([httpAgent, httpAgent]);
const httpsAgents = new Set<Agent>([httpsAgent, httpsAgent]);
const mixedAgents = new Set<Agent>([httpAgent, httpsAgent]);

expect(getAgentsSocketsStats(noAgents).protocol).toEqual('none');
expect(getAgentsSocketsStats(httpAgents).protocol).toEqual('http');
expect(getAgentsSocketsStats(httpsAgents).protocol).toEqual('https');
expect(getAgentsSocketsStats(mixedAgents).protocol).toEqual('mixed');
});

it('does not take into account those Agents that have not had any connection to any node', () => {
const pristineAgentProps = {
sockets: {},
freeSockets: {},
requests: {},
};
const agent1 = getHttpAgentMock(pristineAgentProps);
const agent2 = getHttpAgentMock(pristineAgentProps);
const agent3 = getHttpAgentMock(pristineAgentProps);

const stats = getAgentsSocketsStats(new Set<Agent>([agent1, agent2, agent3]));

expect(stats).toEqual({
averageActiveSocketsPerNode: 0,
averageIdleSocketsPerNode: 0,
connectedNodes: 0,
mostActiveNodeSockets: 0,
mostIdleNodeSockets: 0,
nodesWithActiveSockets: 0,
nodesWithIdleSockets: 0,
protocol: 'none',
totalActiveSockets: 0,
totalIdleSockets: 0,
totalQueuedRequests: 0,
});
});

it('takes into account those Agents that have hold mappings to one or more nodes, but that do not currently have any pending requests, active connections or idle connections', () => {
const emptyAgentProps = {
sockets: {
node1: [],
},
freeSockets: {
node2: [],
},
requests: {
node3: [],
},
};

const agent1 = getHttpAgentMock(emptyAgentProps);
const agent2 = getHttpAgentMock(emptyAgentProps);

const stats = getAgentsSocketsStats(new Set<Agent>([agent1, agent2]));

expect(stats).toEqual({
averageActiveSocketsPerNode: 0,
averageIdleSocketsPerNode: 0,
connectedNodes: 3,
mostActiveNodeSockets: 0,
mostIdleNodeSockets: 0,
nodesWithActiveSockets: 0,
nodesWithIdleSockets: 0,
protocol: 'http',
totalActiveSockets: 0,
totalIdleSockets: 0,
totalQueuedRequests: 0,
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,20 @@
*/

import { NetworkAgent } from '@kbn/core-elasticsearch-client-server-internal';
import { Agent as HttpsAgent } from 'https';
import { mean } from 'lodash';
import type {
ElasticsearchClientProtocol,
ElasticsearchClientsMetrics,
} from '@kbn/core-metrics-server';
import type { ElasticsearchClientsMetrics } from '@kbn/core-metrics-server';

export const getAgentsSocketsStats = (agents: Set<NetworkAgent>): ElasticsearchClientsMetrics => {
const nodes = new Set<string>();
let totalActiveSockets = 0;
let totalIdleSockets = 0;
let totalQueuedRequests = 0;
let http: boolean = false;
let https: boolean = false;

const nodesWithActiveSockets: Record<string, number> = {};
const nodesWithIdleSockets: Record<string, number> = {};

agents.forEach((agent) => {
const agentRequests = Object.entries(agent.requests) ?? [];
const agentSockets = Object.entries(agent.sockets) ?? [];
const agentFreeSockets = Object.entries(agent.freeSockets) ?? [];

if (agentRequests.length || agentSockets.length || agentFreeSockets.length) {
if (agent instanceof HttpsAgent) https = true;
else http = true;

agentRequests.forEach(([node, queue]) => {
nodes.add(node);
totalQueuedRequests += queue?.length ?? 0;
Expand All @@ -43,39 +30,19 @@ export const getAgentsSocketsStats = (agents: Set<NetworkAgent>): ElasticsearchC
nodes.add(node);
const activeSockets = sockets?.length ?? 0;
totalActiveSockets += activeSockets;
nodesWithActiveSockets[node] = (nodesWithActiveSockets[node] ?? 0) + activeSockets;
});

agentFreeSockets.forEach(([node, freeSockets]) => {
nodes.add(node);
const idleSockets = freeSockets?.length ?? 0;
totalIdleSockets += idleSockets;
nodesWithIdleSockets[node] = (nodesWithIdleSockets[node] ?? 0) + idleSockets;
});
}
});

const activeSocketCounters = Object.values(nodesWithActiveSockets);
const idleSocketCounters = Object.values(nodesWithIdleSockets);
const protocol: ElasticsearchClientProtocol = http
? https
? 'mixed'
: 'http'
: https
? 'https'
: 'none';

return {
protocol,
connectedNodes: nodes.size,
nodesWithActiveSockets: activeSocketCounters.filter(Boolean).length,
nodesWithIdleSockets: idleSocketCounters.filter(Boolean).length,
totalActiveSockets,
totalIdleSockets,
totalQueuedRequests,
mostActiveNodeSockets: activeSocketCounters.length ? Math.max(...activeSocketCounters) : 0,
averageActiveSocketsPerNode: activeSocketCounters.length ? mean(activeSocketCounters) : 0,
mostIdleNodeSockets: idleSocketCounters.length ? Math.max(...idleSocketCounters) : 0,
averageIdleSocketsPerNode: idleSocketCounters.length ? mean(idleSocketCounters) : 0,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,9 @@ import type {
} from '@kbn/core-metrics-server';

export const sampleEsClientMetrics: ElasticsearchClientsMetrics = {
protocol: 'https',
connectedNodes: 3,
nodesWithActiveSockets: 3,
nodesWithIdleSockets: 1,
totalActiveSockets: 25,
totalIdleSockets: 2,
totalQueuedRequests: 0,
mostActiveNodeSockets: 15,
averageActiveSocketsPerNode: 8,
mostIdleNodeSockets: 2,
averageIdleSocketsPerNode: 0.5,
};

const createInternalSetupContractMock = () => {
Expand Down
18 changes: 0 additions & 18 deletions packages/core/metrics/core-metrics-server/src/metrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,30 +52,12 @@ export type ElasticsearchClientProtocol = 'none' | 'http' | 'https' | 'mixed';
* @public
*/
export interface ElasticsearchClientsMetrics {
/** The protocol (or protocols) that these Agents are using */
protocol: ElasticsearchClientProtocol;
/** Number of ES nodes that ES-js client is connecting to */
connectedNodes: number;
/** Number of nodes with active connections */
nodesWithActiveSockets: number;
/** Number of nodes with available connections (alive but idle).
* Note that a node can have both active and idle connections at the same time
*/
nodesWithIdleSockets: number;
/** Total number of active sockets (all nodes, all connections) */
totalActiveSockets: number;
/** Total number of available sockets (alive but idle, all nodes, all connections) */
totalIdleSockets: number;
/** Total number of queued requests (all nodes, all connections) */
totalQueuedRequests: number;
/** Number of active connections of the node with most active connections */
mostActiveNodeSockets: number;
/** Average of active sockets per node (all connections) */
averageActiveSocketsPerNode: number;
/** Number of idle connections of the node with most idle connections */
mostIdleNodeSockets: number;
/** Average of available (idle) sockets per node (all connections) */
averageIdleSocketsPerNode: number;
}

/**
Expand Down