Skip to content

Commit

Permalink
[APM][ECO] Add log charts to APM service overview (elastic#191183)
Browse files Browse the repository at this point in the history
closes elastic#190526

### When EEM is enabled (dynamically loads APM and/or Logs overviews):


https://github.com/user-attachments/assets/d645940b-f0fe-42c9-9b3e-d8de4ea23d45


### When EEM is disabled (fallback to standard APM overview page):
_In this example `synth-python` simulates an APM service that hasn't
been processed by EEM yet and that's why it's not available in the video
above._
_`synth_go_logs` is not visible here because it only has logs_


https://github.com/user-attachments/assets/3fc351c6-5ca2-4a07-b00b-5e64bece18d3


## Acceptance criteria

| Status | Name | Description |
| ---- | ---- | ---- |
|✅| **There must be a single service view template** | The view will
adapt based on the available data - there are no 'logs only' or 'APM'
service views |
|✅| **When a service is instrumented with APM, we will show the log rate
and log error % charts at the bottom of the overview** | These will
match any logs with a `logs-*` index pattern |
|☑️ part of it.| **When a service only has logs, the overview tab will
have a dismissible promo visualising a service view with APM** | This
will link to APM documentation, have a CTA to 'Add APM' and also a 'Try
it!' button which points to https://ela.st/demo-service-view |

---------

Co-authored-by: Kate Patticha <aikaterini.patticha@elastic.co>
  • Loading branch information
cauemarcondes and kpatticha authored Aug 30, 2024
1 parent 63ca436 commit d56ea8a
Show file tree
Hide file tree
Showing 26 changed files with 375 additions and 716 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export function LogErrorRateChart({ height }: { height: number }) {
const {
query: { rangeFrom, rangeTo, environment, kuery },
path: { serviceName },
} = useApmParams('/logs-services/{serviceName}');
} = useApmParams('/services/{serviceName}');
const { start, end } = useTimeRange({ rangeFrom, rangeTo });

const { data = INITIAL_STATE, status } = useFetcher(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ export function LogRateChart({ height }: { height: number }) {
const {
query: { rangeFrom, rangeTo, environment, kuery },
path: { serviceName },
} = useApmParams('/logs-services/{serviceName}');

} = useApmParams('/services/{serviceName}');
const { start, end } = useTimeRange({ rangeFrom, rangeTo });

const { data = INITIAL_STATE, status } = useFetcher(
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ const stories: Meta<Args> = {
transactionTypeStatus: FETCH_STATUS.SUCCESS,
transactionTypes: ['request'],
serviceAgentStatus: FETCH_STATUS.SUCCESS,
serviceEntitySummaryStatus: FETCH_STATUS.SUCCESS,
}}
>
<StoryComponent />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,7 @@ export function ServiceDashboards({ checkForEntities = false }: { checkForEntiti
query: { environment, kuery, rangeFrom, rangeTo, dashboardId },
} = useAnyOfApmParams(
'/services/{serviceName}/dashboards',
'/mobile-services/{serviceName}/dashboards',
'/logs-services/{serviceName}/dashboards'
'/mobile-services/{serviceName}/dashboards'
);
const [dashboard, setDashboard] = useState<AwaitingDashboardAPI>();
const [serviceDashboards, setServiceDashboards] = useState<MergedServiceDashboard[]>([]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export function ServiceLogs() {

const {
query: { environment, kuery, rangeFrom, rangeTo },
} = useAnyOfApmParams('/services/{serviceName}/logs', '/logs-services/{serviceName}/logs');
} = useAnyOfApmParams('/services/{serviceName}/logs');

const { start, end } = useTimeRange({ rangeFrom, rangeTo });

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import {
EuiFlexGroup,
EuiFlexGroupProps,
EuiFlexItem,
EuiLink,
EuiPanel,
EuiSpacer,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
import { chartHeight } from '..';
import { AgentName } from '../../../../../typings/es_schemas/ui/fields/agent';
import {
isOpenTelemetryAgentName,
isRumAgentName,
isServerlessAgentName,
} from '../../../../../common/agent_name';
import { useApmServiceContext } from '../../../../context/apm_service/use_apm_service_context';
import { useApmParams } from '../../../../hooks/use_apm_params';
import { useApmRouter } from '../../../../hooks/use_apm_router';
import { useBreakpoints } from '../../../../hooks/use_breakpoints';
import { useTimeRange } from '../../../../hooks/use_time_range';
import { AggregatedTransactionsBadge } from '../../../shared/aggregated_transactions_badge';
import { FailedTransactionRateChart } from '../../../shared/charts/failed_transaction_rate_chart';
import { LatencyChart } from '../../../shared/charts/latency_chart';
import { TransactionBreakdownChart } from '../../../shared/charts/transaction_breakdown_chart';
import { TransactionColdstartRateChart } from '../../../shared/charts/transaction_coldstart_rate_chart';
import { TransactionsTable } from '../../../shared/transactions_table';
import { ServiceOverviewDependenciesTable } from '../service_overview_dependencies_table';
import { ServiceOverviewErrorsTable } from '../service_overview_errors_table';
import { ServiceOverviewInstancesChartAndTable } from '../service_overview_instances_chart_and_table';
import { ServiceOverviewThroughputChart } from '../service_overview_throughput_chart';
import { SloCallout } from '../../../shared/slo_callout';
import { useLocalStorage } from '../../../../hooks/use_local_storage';

const latencyChartHeight = 200;

export function ApmOverview() {
const router = useApmRouter();
const { serviceName, fallbackToTransactions, agentName, serverlessType } = useApmServiceContext();
const {
query,
query: { kuery, environment, rangeFrom, rangeTo, transactionType },
} = useApmParams('/services/{serviceName}/overview');

const { start, end } = useTimeRange({ rangeFrom, rangeTo });

const isRumAgent = isRumAgentName(agentName);
const isOpenTelemetryAgent = isOpenTelemetryAgentName(agentName as AgentName);
const isServerless = isServerlessAgentName(serverlessType);

// The default EuiFlexGroup breaks at 768, but we want to break at 1200, so we
// observe the window width and set the flex directions of rows accordingly
const { isLarge } = useBreakpoints();
const isSingleColumn = isLarge;

const nonLatencyChartHeight = isSingleColumn ? latencyChartHeight : chartHeight;
const rowDirection: EuiFlexGroupProps['direction'] = isSingleColumn ? 'column' : 'row';

const [sloCalloutDismissed, setSloCalloutDismissed] = useLocalStorage(
'apm.sloCalloutDismissed',
false
);

return (
<>
{!sloCalloutDismissed && (
<>
<SloCallout
dismissCallout={() => {
setSloCalloutDismissed(true);
}}
serviceName={serviceName}
environment={environment}
transactionType={transactionType}
/>
<EuiSpacer />
</>
)}
{fallbackToTransactions && (
<EuiFlexItem>
<AggregatedTransactionsBadge />
</EuiFlexItem>
)}
<EuiFlexItem>
<EuiPanel hasBorder={true}>
<LatencyChart height={latencyChartHeight} kuery={kuery} />
</EuiPanel>
</EuiFlexItem>
<EuiFlexItem>
<EuiFlexGroup direction={rowDirection} gutterSize="s" responsive={false}>
<EuiFlexItem grow={3}>
<ServiceOverviewThroughputChart height={nonLatencyChartHeight} kuery={kuery} />
</EuiFlexItem>
<EuiFlexItem grow={7}>
<EuiPanel hasBorder={true}>
<TransactionsTable
kuery={kuery}
environment={environment}
fixedHeight={true}
start={start}
end={end}
showPerPageOptions={false}
numberOfTransactionsPerPage={5}
showSparkPlots={!isSingleColumn}
/>
</EuiPanel>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
<EuiFlexItem>
<EuiFlexGroup direction={rowDirection} gutterSize="s" responsive={false}>
{!isRumAgent && (
<EuiFlexItem grow={3}>
<FailedTransactionRateChart
height={nonLatencyChartHeight}
showAnnotations={false}
kuery={kuery}
/>
</EuiFlexItem>
)}
<EuiFlexItem grow={7}>
<EuiPanel hasBorder={true}>
<ServiceOverviewErrorsTable serviceName={serviceName} />
</EuiPanel>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
<EuiFlexItem>
<EuiFlexGroup direction={rowDirection} gutterSize="s" responsive={false}>
{isServerless ? (
<EuiFlexItem grow={3}>
<TransactionColdstartRateChart
showAnnotations={false}
environment={environment}
kuery={kuery}
/>
</EuiFlexItem>
) : (
!isOpenTelemetryAgent && (
<EuiFlexItem grow={3}>
<TransactionBreakdownChart
showAnnotations={false}
environment={environment}
kuery={kuery}
/>
</EuiFlexItem>
)
)}
{!isRumAgent && (
<EuiFlexItem grow={7}>
<EuiPanel hasBorder={true}>
<ServiceOverviewDependenciesTable
fixedHeight={true}
showPerPageOptions={false}
link={
<EuiLink
data-test-subj="apmServiceOverviewViewDependenciesLink"
href={router.link('/services/{serviceName}/dependencies', {
path: { serviceName },
query,
})}
>
{i18n.translate('xpack.apm.serviceOverview.dependenciesTableTabLink', {
defaultMessage: 'View dependencies',
})}
</EuiLink>
}
showSparkPlots={!isSingleColumn}
/>
</EuiPanel>
</EuiFlexItem>
)}
</EuiFlexGroup>
</EuiFlexItem>
{!isRumAgent && !isServerless && (
<EuiFlexItem>
<EuiFlexGroup direction="column" gutterSize="s" responsive={false}>
<ServiceOverviewInstancesChartAndTable
chartHeight={nonLatencyChartHeight}
serviceName={serviceName}
/>
</EuiFlexGroup>
</EuiFlexItem>
)}
</>
);
}
Loading

0 comments on commit d56ea8a

Please sign in to comment.