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

[Observability AI Assistant] Contextual insights #8

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
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
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -772,7 +772,6 @@
"@opentelemetry/sdk-metrics-base": "^0.31.0",
"@opentelemetry/semantic-conventions": "^1.4.0",
"@reduxjs/toolkit": "1.7.2",
"@sindresorhus/fnv1a": "^3.0.0",
"@slack/webhook": "^5.0.4",
"@tanstack/react-query": "^4.29.12",
"@tanstack/react-query-devtools": "^4.29.12",
Expand Down Expand Up @@ -840,6 +839,7 @@
"fast-deep-equal": "^3.1.1",
"fflate": "^0.6.9",
"file-saver": "^1.3.8",
"fnv-plus": "^1.3.1",
"font-awesome": "4.7.0",
"formik": "^2.2.9",
"fp-ts": "^2.3.1",
Expand Down Expand Up @@ -1437,7 +1437,6 @@
"faker": "^5.1.0",
"fetch-mock": "^7.3.9",
"file-loader": "^4.2.0",
"fnv-plus": "^1.3.1",
"form-data": "^4.0.0",
"geckodriver": "^4.0.0",
"gulp-brotli": "^3.0.0",
Expand Down
8 changes: 5 additions & 3 deletions x-pack/plugins/apm/kibana.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
"dataViews",
"lens",
"maps",
"uiActions"
"uiActions",
"observabilityAIAssistant"
],
"optionalPlugins": [
"actions",
Expand All @@ -47,7 +48,7 @@
"usageCollection",
"customIntegrations", // Move this to requiredPlugins after completely migrating from the Tutorials Home App
"licenseManagement",
"profiling"
"profiling",
],
"requiredBundles": [
"advancedSettings",
Expand All @@ -57,7 +58,8 @@
"ml",
"observability",
"esUiShared",
"maps"
"maps",
"observabilityAIAssistant"
]
}
}
1 change: 1 addition & 0 deletions x-pack/plugins/apm/public/application/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export const renderApp = ({
unifiedSearch: pluginsStart.unifiedSearch,
lens: pluginsStart.lens,
uiActions: pluginsStart.uiActions,
observabilityAIAssistant: pluginsStart.observabilityAIAssistant,
};

// render APM feedback link in global help menu
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* 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 { EuiFlexItem, EuiSpacer } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import {
useObservabilityAIAssistant,
ContextualInsight,
type Message,
MessageRole,
} from '@kbn/observability-ai-assistant-plugin/public';
import React, { useMemo, useState } from 'react';
import { APMError } from '../../../../../typings/es_schemas/ui/apm_error';
import { Transaction } from '../../../../../typings/es_schemas/ui/transaction';
import { ErrorSampleDetailTabContent } from './error_sample_detail';
import { exceptionStacktraceTab, logStacktraceTab } from './error_tabs';

export function ErrorSampleContextualInsight({
error,
transaction,
}: {
error: APMError;
transaction?: Transaction;
}) {
const aiAssistant = useObservabilityAIAssistant();

const [logStacktrace, setLogStacktrace] = useState('');
const [exceptionStacktrace, setExceptionStacktrace] = useState('');

const messages = useMemo<Message[]>(() => {
const now = new Date().toISOString();

const serviceName = error.service.name;
const languageName = error.service.language?.name ?? '';
const runtimeName = error.service.runtime?.name ?? '';
const runtimeVersion = error.service.runtime?.version ?? '';
const transactionName = transaction?.transaction.name ?? '';

return [
{
'@timestamp': now,
message: {
role: MessageRole.System,
content: `You are apm-gpt, a helpful assistant for performance analysis, optimisation and
root cause analysis of software. Answer as concisely as possible.`,
},
},
{
'@timestamp': now,
message: {
role: MessageRole.User,
content: `I'm an SRE. I am looking at an exception and trying to understand what it means.

Your task is to describe what the error means and what it could be caused by.

The error occurred on a service called ${serviceName}, which is a ${runtimeName} service written in ${languageName}. The
runtime version is ${runtimeVersion}.

The request it occurred for is called ${transactionName}.

${
logStacktrace
? `The log stacktrace:
${logStacktrace}`
: ''
}

${
exceptionStacktrace
? `The exception stacktrace:
${exceptionStacktrace}`
: ''
}
`,
},
},
];
}, [error, transaction, logStacktrace, exceptionStacktrace]);

return aiAssistant.isEnabled() && messages ? (
<>
<EuiFlexItem>
<ContextualInsight
messages={messages}
title={i18n.translate(
'xpack.apm.errorGroupContextualInsight.explainErrorTitle',
{ defaultMessage: "What's this error?" }
)}
/>
</EuiFlexItem>
<EuiSpacer size="s" />
<div
ref={(next) => {
setLogStacktrace(next?.innerText ?? '');
}}
style={{ display: 'none' }}
>
{error.error.log?.message && (
<ErrorSampleDetailTabContent
error={error}
currentTab={logStacktraceTab}
/>
)}
</div>
<div
ref={(next) => {
setExceptionStacktrace(next?.innerText ?? '');
}}
style={{ display: 'none' }}
>
{error.error.exception?.length && (
<ErrorSampleDetailTabContent
error={error}
currentTab={exceptionStacktraceTab}
/>
)}
</div>
</>
) : (
<></>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@ import { UserAgentSummaryItem } from '../../../shared/summary/user_agent_summary
import { TimestampTooltip } from '../../../shared/timestamp_tooltip';
import { PlaintextStacktrace } from './plaintext_stacktrace';
import { TransactionTab } from '../../transaction_details/waterfall_with_summary/transaction_tabs';
import { ErrorSampleCoPilotPrompt } from './error_sample_co_pilot_prompt';
import { ErrorTab, ErrorTabKey, getTabs } from './error_tabs';
import { ErrorUiActionsContextMenu } from './error_ui_actions_context_menu';
import { ExceptionStacktrace } from './exception_stacktrace';
import { SampleSummary } from './sample_summary';
import { ErrorSampleContextualInsight } from './error_sample_contextual_insight';

const TransactionLinkName = euiStyled.div`
margin-left: ${({ theme }) => theme.eui.euiSizeS};
Expand Down Expand Up @@ -337,7 +337,7 @@ export function ErrorSampleDetails({
<SampleSummary error={error} />
)}

<ErrorSampleCoPilotPrompt error={error} transaction={transaction} />
<ErrorSampleContextualInsight error={error} transaction={transaction} />

<EuiTabs>
{tabs.map(({ key, label }) => {
Expand Down
37 changes: 19 additions & 18 deletions x-pack/plugins/apm/public/components/routing/app_root/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@ import {
useUiSetting$,
} from '@kbn/kibana-react-plugin/public';
import { Storage } from '@kbn/kibana-utils-plugin/public';
import { InspectorContextProvider } from '@kbn/observability-shared-plugin/public';
import { HeaderMenuPortal } from '@kbn/observability-shared-plugin/public';
import { ObservabilityAIAssistantProvider } from '@kbn/observability-ai-assistant-plugin/public';
import {
HeaderMenuPortal,
InspectorContextProvider,
} from '@kbn/observability-shared-plugin/public';
import { Route } from '@kbn/shared-ux-router';
import { RouteRenderer, RouterProvider } from '@kbn/typed-react-router-config';
import { euiDarkVars, euiLightVars } from '@kbn/ui-theme';
import React from 'react';
import { Route } from '@kbn/shared-ux-router';
import { DefaultTheme, ThemeProvider } from 'styled-components';
import { CoPilotContextProvider } from '@kbn/observability-plugin/public';
import { AnomalyDetectionJobsContextProvider } from '../../../context/anomaly_detection_jobs/anomaly_detection_jobs_context';
import {
ApmPluginContext,
Expand All @@ -31,15 +33,15 @@ import { LicenseProvider } from '../../../context/license/license_context';
import { TimeRangeIdContextProvider } from '../../../context/time_range_id/time_range_id_context';
import { UrlParamsProvider } from '../../../context/url_params_context/url_params_context';
import { ApmPluginStartDeps } from '../../../plugin';
import { ScrollToTopOnPathChange } from './scroll_to_top_on_path_change';
import { ApmErrorBoundary } from '../apm_error_boundary';
import { apmRouter } from '../apm_route_config';
import { TrackPageview } from '../track_pageview';
import { ApmHeaderActionMenu } from './apm_header_action_menu';
import { RedirectDependenciesToDependenciesInventory } from './redirect_dependencies_to_dependencies_inventory';
import { RedirectWithDefaultDateRange } from './redirect_with_default_date_range';
import { RedirectWithDefaultEnvironment } from './redirect_with_default_environment';
import { RedirectWithOffset } from './redirect_with_offset';
import { ApmErrorBoundary } from '../apm_error_boundary';
import { apmRouter } from '../apm_route_config';
import { RedirectDependenciesToDependenciesInventory } from './redirect_dependencies_to_dependencies_inventory';
import { TrackPageview } from '../track_pageview';
import { ScrollToTopOnPathChange } from './scroll_to_top_on_path_change';
import { UpdateExecutionContextOnRouteChange } from './update_execution_context_on_route_change';

const storage = new Storage(localStorage);
Expand All @@ -55,9 +57,6 @@ export function ApmAppRoot({
const { history } = appMountParameters;
const i18nCore = core.i18n;

const coPilotService =
apmPluginContextValue.plugins.observability.getCoPilotService();

return (
<RedirectAppLinks
application={core.application}
Expand All @@ -68,9 +67,11 @@ export function ApmAppRoot({
<ApmPluginContext.Provider value={apmPluginContextValue}>
<KibanaContextProvider services={{ ...core, ...pluginsStart, storage }}>
<i18nCore.Context>
<TimeRangeIdContextProvider>
<RouterProvider history={history} router={apmRouter as any}>
<CoPilotContextProvider value={coPilotService}>
<ObservabilityAIAssistantProvider
value={apmPluginContextValue.observabilityAIAssistant}
>
<TimeRangeIdContextProvider>
<RouterProvider history={history} router={apmRouter as any}>
<ApmErrorBoundary>
<RedirectDependenciesToDependenciesInventory>
<RedirectWithDefaultEnvironment>
Expand Down Expand Up @@ -105,9 +106,9 @@ export function ApmAppRoot({
</RedirectWithDefaultEnvironment>
</RedirectDependenciesToDependenciesInventory>
</ApmErrorBoundary>
</CoPilotContextProvider>
</RouterProvider>
</TimeRangeIdContextProvider>
</RouterProvider>
</TimeRangeIdContextProvider>
</ObservabilityAIAssistantProvider>
</i18nCore.Context>
</KibanaContextProvider>
</ApmPluginContext.Provider>
Expand Down
Loading