Skip to content

Commit

Permalink
Typescript migration for the transaction endpoints (#24397)
Browse files Browse the repository at this point in the history
  • Loading branch information
sorenlouv authored Oct 23, 2018
1 parent 1095893 commit 994d566
Show file tree
Hide file tree
Showing 11 changed files with 155 additions and 83 deletions.
14 changes: 10 additions & 4 deletions x-pack/plugins/apm/public/services/rest/apm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
// @ts-ignore
import { camelizeKeys } from 'humps';
import { isEmpty } from 'lodash';
import { ServiceResponse } from 'x-pack/plugins/apm/server/lib/services/get_service';
import { ServiceListItemResponse } from 'x-pack/plugins/apm/server/lib/services/get_services';
import { IDistributionResponse } from 'x-pack/plugins/apm/server/lib/transactions/distribution/get_distribution';
import { Span } from 'x-pack/plugins/apm/typings/Span';
import { Transaction } from 'x-pack/plugins/apm/typings/Transaction';
Expand Down Expand Up @@ -53,7 +55,11 @@ export async function getEncodedEsQuery(kuery?: string) {
return encodeURIComponent(JSON.stringify(esFilterQuery));
}

export async function loadServiceList({ start, end, kuery }: IUrlParams) {
export async function loadServiceList({
start,
end,
kuery
}: IUrlParams): Promise<ServiceListItemResponse> {
return callApi({
pathname: `/api/apm/services`,
query: {
Expand All @@ -69,7 +75,7 @@ export async function loadServiceDetails({
start,
end,
kuery
}: IUrlParams) {
}: IUrlParams): Promise<ServiceResponse> {
return callApi({
pathname: `/api/apm/services/${serviceName}`,
query: {
Expand Down Expand Up @@ -151,7 +157,7 @@ export async function loadSpans({
start,
end,
transactionId
}: IUrlParams) {
}: IUrlParams): Promise<Span[]> {
const hits: Span[] = await callApi({
pathname: `/api/apm/services/${serviceName}/transactions/${transactionId}/spans`,
query: {
Expand Down Expand Up @@ -189,7 +195,7 @@ export async function loadTransaction({
traceId,
kuery
}: IUrlParams) {
const result = await callApi(
const result: Transaction = await callApi(
{
pathname: `/api/apm/services/${serviceName}/transactions/${transactionId}`,
query: {
Expand Down
26 changes: 14 additions & 12 deletions x-pack/plugins/apm/server/lib/helpers/setup_request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,22 @@

/* tslint:disable no-console */
import { SearchParams, SearchResponse } from 'elasticsearch';
import { Request, Server } from 'hapi';
import moment from 'moment';
import { Url } from 'url';
import { StringMap } from '../../../typings/common';

function decodeEsQuery(esQuery?: string): object {
return esQuery ? JSON.parse(decodeURIComponent(esQuery)) : null;
}

// TODO: get these from hapi
interface Request {
query: StringMap;
server: any;
method: string;
url: Url;
interface KibanaServer extends Server {
config: () => KibanaConfig;
}

interface ServerConfig {
interface KibanaRequest extends Request {
server: KibanaServer;
}

interface KibanaConfig {
get: (key: string) => any;
}

Expand All @@ -31,12 +30,15 @@ type Client<T> = (type: string, params: SearchParams) => SearchResponse<T>;
export interface Setup<T = any> {
start: number;
end: number;
esFilterQuery: object;
esFilterQuery: any;
client: Client<T>;
config: ServerConfig;
config: KibanaConfig;
}

export function setupRequest(req: Request, reply: (setup: Setup) => void) {
export function setupRequest(
req: KibanaRequest,
reply: (setup: Setup) => void
) {
const cluster = req.server.plugins.elasticsearch.getCluster('data');

function client<T>(type: string, params: SearchParams): SearchResponse<T> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ interface ITransactionGroupSample {
context: Transaction['context'];
}

interface ITransactionGroupBucket {
export interface ITransactionGroupBucket {
key: string;
doc_count: number;
avg: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,25 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { get } from 'lodash';
import { oc } from 'ts-optchain';
import { TermsAggsBucket } from 'x-pack/plugins/apm/typings/elasticsearch';
import {
SERVICE_AGENT_NAME,
SERVICE_NAME,
TRANSACTION_TYPE,
SERVICE_AGENT_NAME
TRANSACTION_TYPE
} from '../../../common/constants';
import { Setup } from '../helpers/setup_request';

export async function getService({ serviceName, setup }) {
export interface ServiceResponse {
service_name: string;
types: string[];
agent_name?: string;
}

export async function getService(
serviceName: string,
setup: Setup
): Promise<ServiceResponse> {
const { start, end, esFilterQuery, client, config } = setup;

const params = {
Expand Down Expand Up @@ -52,11 +63,21 @@ export async function getService({ serviceName, setup }) {
params.body.query.bool.filter.push(esFilterQuery);
}

interface Aggs {
types: {
buckets: TermsAggsBucket[];
};
agents: {
buckets: TermsAggsBucket[];
};
}

const resp = await client('search', params);
const aggs: Aggs = resp.aggregations;

return {
service_name: serviceName,
types: resp.aggregations.types.buckets.map(bucket => bucket.key),
agent_name: get(resp, 'aggregations.agents.buckets[0].key')
types: aggs.types.buckets.map(bucket => bucket.key),
agent_name: oc(aggs).agents.buckets[0].key()
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,27 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { oc } from 'ts-optchain';
import { TermsAggsBucket } from 'x-pack/plugins/apm/typings/elasticsearch';
import {
SERVICE_NAME,
TRANSACTION_DURATION,
PROCESSOR_EVENT,
SERVICE_AGENT_NAME,
PROCESSOR_EVENT
SERVICE_NAME,
TRANSACTION_DURATION
} from '../../../common/constants';
import { get } from 'lodash';
import { Setup } from '../helpers/setup_request';

export interface ServiceListItemResponse {
service_name: string;
agent_name: string | undefined;
transactions_per_minute: number;
errors_per_minute: number;
avg_response_time: number;
}

export async function getServices({ setup }) {
export async function getServices(
setup: Setup
): Promise<ServiceListItemResponse[]> {
const { start, end, esFilterQuery, client, config } = setup;

const params = {
Expand Down Expand Up @@ -71,26 +83,43 @@ export async function getServices({ setup }) {
params.body.query.bool.filter.push(esFilterQuery);
}

interface ServiceBucket extends TermsAggsBucket {
avg: {
value: number;
};
agents: {
buckets: TermsAggsBucket[];
};
events: {
buckets: TermsAggsBucket[];
};
}

interface Aggs extends TermsAggsBucket {
services: {
buckets: ServiceBucket[];
};
}

const resp = await client('search', params);
const aggs: Aggs = resp.aggregations;
const serviceBuckets = oc(aggs).services.buckets([]);

const buckets = get(resp.aggregations, 'services.buckets', []);
return buckets.map(bucket => {
return serviceBuckets.map(bucket => {
const eventTypes = bucket.events.buckets;

const transactions = eventTypes.find(e => e.key === 'transaction');
const totalTransactions = get(transactions, 'doc_count', 0);
const totalTransactions = oc(transactions).doc_count(0);

const errors = eventTypes.find(e => e.key === 'error');
const totalErrors = get(errors, 'doc_count', 0);
const totalErrors = oc(errors).doc_count(0);

const deltaAsMinutes = (end - start) / 1000 / 60;

const transactionsPerMinute = totalTransactions / deltaAsMinutes;
const errorsPerMinute = totalErrors / deltaAsMinutes;

return {
service_name: bucket.key,
agent_name: get(bucket, 'agents.buckets[0].key', null),
agent_name: oc(bucket).agents.buckets[0].key(),
transactions_per_minute: transactionsPerMinute,
errors_per_minute: errorsPerMinute,
avg_response_time: bucket.avg.value
Expand Down
18 changes: 9 additions & 9 deletions x-pack/plugins/apm/server/lib/traces/get_top_traces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,22 @@
*/

import { SearchResponse } from 'elasticsearch';
import { oc } from 'ts-optchain';
import { get } from 'lodash';
import {
PARENT_ID,
PROCESSOR_EVENT,
TRACE_ID
} from '../../../common/constants';
import { StringMap } from '../../../typings/common';
import { Transaction } from '../../../typings/Transaction';
import { ITransactionGroup } from '../../../typings/TransactionGroup';
import { Setup } from '../helpers/setup_request';
import {
ITransactionGroupBucket,
prepareTransactionGroups,
TRANSACTION_GROUP_AGGREGATES
} from '../helpers/transaction_group_query';

export async function getTopTraces({
setup
}: {
setup: StringMap<any>;
}): Promise<ITransactionGroup[]> {
export async function getTopTraces(setup: Setup): Promise<ITransactionGroup[]> {
const { start, end, esFilterQuery, client, config } = setup;

const params = {
Expand Down Expand Up @@ -70,8 +67,11 @@ export async function getTopTraces({
}

const response: SearchResponse<Transaction> = await client('search', params);
// @ts-ignore
const buckets = oc(response).aggregations.transactions.buckets([]);
const buckets: ITransactionGroupBucket[] = get(
response.aggregations,
'transactions.buckets',
[]
);

return prepareTransactionGroups({ buckets, start, end });
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,24 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { SearchParams, SearchResponse } from 'elasticsearch';
import { oc } from 'ts-optchain';
import { Transaction } from 'x-pack/plugins/apm/typings/Transaction';
import {
TRANSACTION_ID,
PROCESSOR_EVENT,
TRACE_ID
TRACE_ID,
TRANSACTION_ID
} from '../../../common/constants';
import { get } from 'lodash';
import { Setup } from '../helpers/setup_request';

async function getTransaction({ transactionId, traceId, setup }) {
export async function getTransaction(
transactionId: string,
traceId: string | undefined,
setup: Setup
) {
const { start, end, esFilterQuery, client, config } = setup;

const params = {
const params: SearchParams = {
index: config.get('apm_oss.transactionIndices'),
body: {
size: 1,
Expand Down Expand Up @@ -46,8 +53,6 @@ async function getTransaction({ transactionId, traceId, setup }) {
params.body.query.bool.filter.push({ term: { [TRACE_ID]: traceId } });
}

const resp = await client('search', params);
return get(resp, 'hits.hits[0]._source', {});
const resp: SearchResponse<Transaction> = await client('search', params);
return oc(resp).hits.hits[0]._source();
}

export default getTransaction;
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,22 @@
*/

import Boom from 'boom';
import { getServices } from '../lib/services/get_services';
import { getService } from '../lib/services/get_service';
import { setupRequest } from '../lib/helpers/setup_request';
import { IReply, Request, Server } from 'hapi';
import { withDefaultValidators } from '../lib/helpers/input_validation';
import { setupRequest } from '../lib/helpers/setup_request';
import { getService } from '../lib/services/get_service';
import { getServices } from '../lib/services/get_services';

const ROOT = '/api/apm/services';
const pre = [{ method: setupRequest, assign: 'setup' }];
const defaultErrorHandler = reply => err => {
const defaultErrorHandler = (reply: IReply) => (err: Error) => {
// tslint:disable-next-line
console.error(err.stack);
// @ts-ignore
reply(Boom.wrap(err, 400));
};

export function initServicesApi(server) {
export function initServicesApi(server: Server) {
server.route({
method: 'GET',
path: ROOT,
Expand All @@ -27,9 +30,9 @@ export function initServicesApi(server) {
query: withDefaultValidators()
}
},
handler: (req, reply) => {
handler: (req: Request, reply: IReply) => {
const { setup } = req.pre;
return getServices({ setup })
return getServices(setup)
.then(reply)
.catch(defaultErrorHandler(reply));
}
Expand All @@ -44,10 +47,10 @@ export function initServicesApi(server) {
query: withDefaultValidators()
}
},
handler: (req, reply) => {
handler: (req: Request, reply: IReply) => {
const { setup } = req.pre;
const { serviceName } = req.params;
return getService({ serviceName, setup })
return getService(serviceName, setup)
.then(reply)
.catch(defaultErrorHandler(reply));
}
Expand Down
Loading

0 comments on commit 994d566

Please sign in to comment.