From 994d5664b1284576b242e21cd6398cae0273f036 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Louv-Jansen?= Date: Tue, 23 Oct 2018 18:39:18 +0200 Subject: [PATCH] Typescript migration for the transaction endpoints (#24397) --- .../plugins/apm/public/services/rest/apm.ts | 14 +++-- ...nput_validation.js => input_validation.ts} | 0 .../apm/server/lib/helpers/setup_request.ts | 26 ++++----- .../lib/helpers/transaction_group_query.ts | 2 +- .../{get_service.js => get_service.ts} | 33 +++++++++--- .../{get_services.js => get_services.ts} | 53 ++++++++++++++----- .../apm/server/lib/traces/get_top_traces.ts | 18 +++---- ...{get_transaction.js => get_transaction.ts} | 23 ++++---- .../routes/{services.js => services.ts} | 21 ++++---- .../server/routes/{traces.js => traces.ts} | 17 +++--- .../{transactions.js => transactions.ts} | 31 ++++++----- 11 files changed, 155 insertions(+), 83 deletions(-) rename x-pack/plugins/apm/server/lib/helpers/{input_validation.js => input_validation.ts} (100%) rename x-pack/plugins/apm/server/lib/services/{get_service.js => get_service.ts} (64%) rename x-pack/plugins/apm/server/lib/services/{get_services.js => get_services.ts} (67%) rename x-pack/plugins/apm/server/lib/transactions/{get_transaction.js => get_transaction.ts} (67%) rename x-pack/plugins/apm/server/routes/{services.js => services.ts} (76%) rename x-pack/plugins/apm/server/routes/{traces.js => traces.ts} (79%) rename x-pack/plugins/apm/server/routes/{transactions.js => transactions.ts} (85%) diff --git a/x-pack/plugins/apm/public/services/rest/apm.ts b/x-pack/plugins/apm/public/services/rest/apm.ts index 71e9d73241bc8..60e5fbc703ac6 100644 --- a/x-pack/plugins/apm/public/services/rest/apm.ts +++ b/x-pack/plugins/apm/public/services/rest/apm.ts @@ -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'; @@ -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 { return callApi({ pathname: `/api/apm/services`, query: { @@ -69,7 +75,7 @@ export async function loadServiceDetails({ start, end, kuery -}: IUrlParams) { +}: IUrlParams): Promise { return callApi({ pathname: `/api/apm/services/${serviceName}`, query: { @@ -151,7 +157,7 @@ export async function loadSpans({ start, end, transactionId -}: IUrlParams) { +}: IUrlParams): Promise { const hits: Span[] = await callApi({ pathname: `/api/apm/services/${serviceName}/transactions/${transactionId}/spans`, query: { @@ -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: { diff --git a/x-pack/plugins/apm/server/lib/helpers/input_validation.js b/x-pack/plugins/apm/server/lib/helpers/input_validation.ts similarity index 100% rename from x-pack/plugins/apm/server/lib/helpers/input_validation.js rename to x-pack/plugins/apm/server/lib/helpers/input_validation.ts diff --git a/x-pack/plugins/apm/server/lib/helpers/setup_request.ts b/x-pack/plugins/apm/server/lib/helpers/setup_request.ts index df780b3869892..b5bc84634dd3d 100644 --- a/x-pack/plugins/apm/server/lib/helpers/setup_request.ts +++ b/x-pack/plugins/apm/server/lib/helpers/setup_request.ts @@ -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; } @@ -31,12 +30,15 @@ type Client = (type: string, params: SearchParams) => SearchResponse; export interface Setup { start: number; end: number; - esFilterQuery: object; + esFilterQuery: any; client: Client; - 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(type: string, params: SearchParams): SearchResponse { diff --git a/x-pack/plugins/apm/server/lib/helpers/transaction_group_query.ts b/x-pack/plugins/apm/server/lib/helpers/transaction_group_query.ts index 315c5e0b21be4..66ec2d7986030 100644 --- a/x-pack/plugins/apm/server/lib/helpers/transaction_group_query.ts +++ b/x-pack/plugins/apm/server/lib/helpers/transaction_group_query.ts @@ -18,7 +18,7 @@ interface ITransactionGroupSample { context: Transaction['context']; } -interface ITransactionGroupBucket { +export interface ITransactionGroupBucket { key: string; doc_count: number; avg: { diff --git a/x-pack/plugins/apm/server/lib/services/get_service.js b/x-pack/plugins/apm/server/lib/services/get_service.ts similarity index 64% rename from x-pack/plugins/apm/server/lib/services/get_service.js rename to x-pack/plugins/apm/server/lib/services/get_service.ts index 416dfaf3746c4..2998f3487ecc6 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service.js +++ b/x-pack/plugins/apm/server/lib/services/get_service.ts @@ -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 { const { start, end, esFilterQuery, client, config } = setup; const params = { @@ -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() }; } diff --git a/x-pack/plugins/apm/server/lib/services/get_services.js b/x-pack/plugins/apm/server/lib/services/get_services.ts similarity index 67% rename from x-pack/plugins/apm/server/lib/services/get_services.js rename to x-pack/plugins/apm/server/lib/services/get_services.ts index 37da74123ffdd..eeb39c256e8a3 100644 --- a/x-pack/plugins/apm/server/lib/services/get_services.js +++ b/x-pack/plugins/apm/server/lib/services/get_services.ts @@ -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 { const { start, end, esFilterQuery, client, config } = setup; const params = { @@ -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 diff --git a/x-pack/plugins/apm/server/lib/traces/get_top_traces.ts b/x-pack/plugins/apm/server/lib/traces/get_top_traces.ts index 7f1141f6fa008..990879690d9b7 100644 --- a/x-pack/plugins/apm/server/lib/traces/get_top_traces.ts +++ b/x-pack/plugins/apm/server/lib/traces/get_top_traces.ts @@ -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; -}): Promise { +export async function getTopTraces(setup: Setup): Promise { const { start, end, esFilterQuery, client, config } = setup; const params = { @@ -70,8 +67,11 @@ export async function getTopTraces({ } const response: SearchResponse = 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 }); } diff --git a/x-pack/plugins/apm/server/lib/transactions/get_transaction.js b/x-pack/plugins/apm/server/lib/transactions/get_transaction.ts similarity index 67% rename from x-pack/plugins/apm/server/lib/transactions/get_transaction.js rename to x-pack/plugins/apm/server/lib/transactions/get_transaction.ts index c3f6076599120..c8494f366a2d4 100644 --- a/x-pack/plugins/apm/server/lib/transactions/get_transaction.js +++ b/x-pack/plugins/apm/server/lib/transactions/get_transaction.ts @@ -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, @@ -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 = await client('search', params); + return oc(resp).hits.hits[0]._source(); } - -export default getTransaction; diff --git a/x-pack/plugins/apm/server/routes/services.js b/x-pack/plugins/apm/server/routes/services.ts similarity index 76% rename from x-pack/plugins/apm/server/routes/services.js rename to x-pack/plugins/apm/server/routes/services.ts index 90a3d923800ba..fab8b7809ee7e 100644 --- a/x-pack/plugins/apm/server/routes/services.js +++ b/x-pack/plugins/apm/server/routes/services.ts @@ -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, @@ -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)); } @@ -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)); } diff --git a/x-pack/plugins/apm/server/routes/traces.js b/x-pack/plugins/apm/server/routes/traces.ts similarity index 79% rename from x-pack/plugins/apm/server/routes/traces.js rename to x-pack/plugins/apm/server/routes/traces.ts index 75b27fb200b04..737f1d48cbf9a 100644 --- a/x-pack/plugins/apm/server/routes/traces.js +++ b/x-pack/plugins/apm/server/routes/traces.ts @@ -5,19 +5,22 @@ */ import Boom from 'boom'; -import { setupRequest } from '../lib/helpers/setup_request'; +import { IReply, Request, Server } from 'hapi'; import { withDefaultValidators } from '../lib/helpers/input_validation'; -import { getTrace } from '../lib/traces/get_trace'; +import { setupRequest } from '../lib/helpers/setup_request'; import { getTopTraces } from '../lib/traces/get_top_traces'; +import { getTrace } from '../lib/traces/get_trace'; const pre = [{ method: setupRequest, assign: 'setup' }]; const ROOT = '/api/apm/traces'; -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 initTracesApi(server) { +export function initTracesApi(server: Server) { // Get trace list server.route({ method: 'GET', @@ -28,10 +31,10 @@ export function initTracesApi(server) { query: withDefaultValidators() } }, - handler: (req, reply) => { + handler: (req: Request, reply: IReply) => { const { setup } = req.pre; - return getTopTraces({ setup }) + return getTopTraces(setup) .then(reply) .catch(defaultErrorHandler(reply)); } @@ -47,7 +50,7 @@ export function initTracesApi(server) { query: withDefaultValidators() } }, - handler: (req, reply) => { + handler: (req: Request, reply: IReply) => { const { traceId } = req.params; const { setup } = req.pre; return getTrace(traceId, setup) diff --git a/x-pack/plugins/apm/server/routes/transactions.js b/x-pack/plugins/apm/server/routes/transactions.ts similarity index 85% rename from x-pack/plugins/apm/server/routes/transactions.js rename to x-pack/plugins/apm/server/routes/transactions.ts index d6bf0da9385c2..623fddb31a2e6 100644 --- a/x-pack/plugins/apm/server/routes/transactions.js +++ b/x-pack/plugins/apm/server/routes/transactions.ts @@ -4,25 +4,28 @@ * you may not use this file except in compliance with the Elastic License. */ -import Joi from 'joi'; import Boom from 'boom'; - +import { IReply, Request, Server } from 'hapi'; +import Joi from 'joi'; +import { withDefaultValidators } from '../lib/helpers/input_validation'; +import { setupRequest } from '../lib/helpers/setup_request'; +// @ts-ignore import { getTimeseriesData } from '../lib/transactions/charts/get_timeseries_data'; -import { getSpans } from '../lib/transactions/spans/get_spans'; import { getDistribution } from '../lib/transactions/distribution/get_distribution'; import { getTopTransactions } from '../lib/transactions/get_top_transactions'; -import getTransaction from '../lib/transactions/get_transaction'; -import { setupRequest } from '../lib/helpers/setup_request'; -import { withDefaultValidators } from '../lib/helpers/input_validation'; +import { getTransaction } from '../lib/transactions/get_transaction'; +import { getSpans } from '../lib/transactions/spans/get_spans'; const pre = [{ method: setupRequest, assign: 'setup' }]; const ROOT = '/api/apm/services/{serviceName}/transactions'; -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 initTransactionsApi(server) { +export function initTransactionsApi(server: Server) { server.route({ method: 'GET', path: ROOT, @@ -35,7 +38,7 @@ export function initTransactionsApi(server) { }) } }, - handler: (req, reply) => { + handler: (req: Request, reply: IReply) => { const { serviceName } = req.params; const { transaction_type: transactionType } = req.query; const { setup } = req.pre; @@ -61,11 +64,11 @@ export function initTransactionsApi(server) { }) } }, - handler: (req, reply) => { + handler: (req: Request, reply: IReply) => { const { transactionId } = req.params; const { traceId } = req.query; const { setup } = req.pre; - return getTransaction({ transactionId, traceId, setup }) + return getTransaction(transactionId, traceId, setup) .then(reply) .catch(defaultErrorHandler(reply)); } @@ -80,7 +83,7 @@ export function initTransactionsApi(server) { query: withDefaultValidators() } }, - handler: (req, reply) => { + handler: (req: Request, reply: IReply) => { const { transactionId } = req.params; const { setup } = req.pre; return getSpans(transactionId, setup) @@ -102,7 +105,7 @@ export function initTransactionsApi(server) { }) } }, - handler: (req, reply) => { + handler: (req: Request, reply: IReply) => { const { setup } = req.pre; const { serviceName } = req.params; const transactionType = req.query.transaction_type; @@ -130,7 +133,7 @@ export function initTransactionsApi(server) { }) } }, - handler: (req, reply) => { + handler: (req: Request, reply: IReply) => { const { setup } = req.pre; const { serviceName } = req.params; const { transaction_name: transactionName } = req.query;