Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
c9aab67
Added Remediation Steps to Log Ai Insight system promt
yuliia-fryshko Dec 22, 2025
44b44e2
edited system promt
yuliia-fryshko Dec 23, 2025
b64015b
added downstream dependencies
yuliia-fryshko Dec 28, 2025
a87c1dc
added trace data
yuliia-fryshko Dec 28, 2025
e5d48e5
Merge branch 'main' into edit-log-insight-system-promt-445
yuliia-fryshko Dec 29, 2025
e02947c
edit log ai system promt to respond base on log type
yuliia-fryshko Dec 29, 2025
769fee0
edited wording
yuliia-fryshko Dec 29, 2025
e50dd81
Merge branch 'main' into edit-log-insight-system-promt-445
yuliia-fryshko Dec 31, 2025
52ee4df
Update x-pack/solutions/observability/plugins/observability_agent_bui…
yuliia-fryshko Dec 31, 2025
ac070e8
Update x-pack/solutions/observability/plugins/observability_agent_bui…
yuliia-fryshko Dec 31, 2025
b8c86ee
Changes from node scripts/eslint_all_files --no-cache --fix
kibanamachine Dec 31, 2025
b0685ce
applied PR review suggestions
yuliia-fryshko Dec 31, 2025
55affb9
removed first occurence promt
yuliia-fryshko Dec 31, 2025
0b45ec5
Merge branch 'main' into edit-log-insight-system-promt-445
yuliia-fryshko Jan 4, 2026
3124e3a
Merge branch 'main' into edit-log-insight-system-promt-445
yuliia-fryshko Jan 9, 2026
e1309f1
Merge branch 'main' into edit-log-insight-system-promt-445
yuliia-fryshko Jan 13, 2026
2112716
Merge branch 'main' into edit-log-insight-system-promt-445
yuliia-fryshko Jan 13, 2026
a57c8be
Merge branch 'main' into edit-log-insight-system-promt-445
yuliia-fryshko Jan 13, 2026
384bced
prefetched data base on log severity
yuliia-fryshko Jan 14, 2026
2523a21
removed redundant fallback
yuliia-fryshko Jan 14, 2026
35b7291
added a condition to identify id the log is an error
yuliia-fryshko Jan 14, 2026
0e6ac58
rename getToolHandler import to getCorrelatedLogs
yuliia-fryshko Jan 14, 2026
2ad03d3
adjusted fields according to mapping ecs-otel
yuliia-fryshko Jan 16, 2026
ab652c6
adjusted correlated log sequence
yuliia-fryshko Jan 16, 2026
94135cc
Changes from node scripts/eslint_all_files --no-cache --fix
kibanamachine Jan 16, 2026
35ec4bd
added API test for Log AI Insight
yuliia-fryshko Jan 16, 2026
d9b647f
addressed review comment
yuliia-fryshko Jan 16, 2026
07ce96a
Merge branch 'main' into edit-log-insight-system-promt-445
yuliia-fryshko Jan 16, 2026
f4382fe
fix type check
yuliia-fryshko Jan 16, 2026
c5d3a6f
fixed check type
yuliia-fryshko Jan 19, 2026
ae8568f
Merge branch 'main' into edit-log-insight-system-promt-445
yuliia-fryshko Jan 19, 2026
6fd1ce8
Merge branch 'main' into edit-log-insight-system-promt-445
yuliia-fryshko Jan 21, 2026
33b4b6b
prefetch correlation logs for all log types
yuliia-fryshko Jan 22, 2026
6130807
fix merge conflict
yuliia-fryshko Jan 22, 2026
f009254
fix merge conflict
yuliia-fryshko Jan 22, 2026
5ce23e8
Merge branch 'main' into edit-log-insight-system-promt-445
yuliia-fryshko Jan 22, 2026
2423a38
search ecs fields instead of source
yuliia-fryshko Jan 22, 2026
e56b156
Merge branch 'main' into edit-log-insight-system-promt-445
yuliia-fryshko Jan 27, 2026
d70c2fd
Merge branch 'main' into edit-log-insight-system-promt-445
yuliia-fryshko Jan 28, 2026
c907227
fixed merge conflicts
yuliia-fryshko Jan 28, 2026
5dc626c
added categorised logs and default values for correlation tool handler
yuliia-fryshko Jan 28, 2026
73ccf32
Update x-pack/solutions/observability/plugins/observability_agent_bui…
yuliia-fryshko Jan 28, 2026
bd60b60
Update x-pack/solutions/observability/plugins/observability_agent_bui…
yuliia-fryshko Jan 28, 2026
cf98e3a
Update x-pack/solutions/observability/plugins/observability_agent_bui…
yuliia-fryshko Jan 28, 2026
5c124c5
Changes from node scripts/eslint_all_files --no-cache --fix
kibanamachine Jan 28, 2026
e9fd179
fix review comments
yuliia-fryshko Jan 28, 2026
8a6da49
Merge branch 'main' into edit-log-insight-system-promt-445
yuliia-fryshko Jan 28, 2026
7bbe53d
Update x-pack/solutions/observability/plugins/observability_agent_bui…
yuliia-fryshko Jan 28, 2026
b220f84
fixed tests
yuliia-fryshko Jan 28, 2026
7719f35
moved the function to utils
yuliia-fryshko Jan 28, 2026
15fa737
Update x-pack/solutions/observability/test/api_integration_deployment…
yuliia-fryshko Jan 29, 2026
c389435
Update x-pack/solutions/observability/plugins/observability_agent_bui…
yuliia-fryshko Jan 29, 2026
efb1d96
Update x-pack/solutions/observability/plugins/observability_agent_bui…
yuliia-fryshko Jan 29, 2026
1dea11f
Update x-pack/solutions/observability/test/api_integration_deployment…
yuliia-fryshko Jan 29, 2026
1973cbd
Changes from node scripts/eslint_all_files --no-cache --fix
kibanamachine Jan 29, 2026
775b93c
fixed review comments
yuliia-fryshko Jan 29, 2026
ab0c124
Merge branch 'main' into edit-log-insight-system-promt-445
yuliia-fryshko Jan 29, 2026
01b7d1b
Merge branch 'main' into edit-log-insight-system-promt-445
yuliia-fryshko Jan 29, 2026
ca63002
fixed merge conflict
yuliia-fryshko Jan 29, 2026
53f8492
fix duplicates, add shared test helpers
yuliia-fryshko Jan 29, 2026
e95c9c2
Changes from node scripts/lint_ts_projects --fix
kibanamachine Jan 29, 2026
0b5b0cd
Changes from node scripts/regenerate_moon_projects.js --update
kibanamachine Jan 29, 2026
58c53df
Merge branch 'main' into edit-log-insight-system-promt-445
yuliia-fryshko Jan 29, 2026
e6bee31
Changes from node scripts/eslint_all_files --no-cache --fix
kibanamachine Jan 29, 2026
841558f
Merge branch 'main' into edit-log-insight-system-promt-445
yuliia-fryshko Jan 29, 2026
8d98f5c
removed categorised logs; fixed check type
yuliia-fryshko Jan 29, 2026
3b2bda0
added ditributed trace data when error
yuliia-fryshko Jan 30, 2026
95c5a02
Changes from node scripts/eslint_all_files --no-cache --fix
kibanamachine Jan 30, 2026
a4af6d0
removed duplications of tests
yuliia-fryshko Jan 30, 2026
f752200
removed distributed trace
yuliia-fryshko Jan 30, 2026
5d835e2
fix tests
yuliia-fryshko Jan 30, 2026
306143a
Update x-pack/solutions/observability/plugins/observability_agent_bui…
yuliia-fryshko Jan 30, 2026
90e3885
created a function to call corelated logs
yuliia-fryshko Jan 30, 2026
6c67d8d
Update x-pack/solutions/observability/plugins/observability_agent_bui…
yuliia-fryshko Jan 30, 2026
b47a1e6
fixed review comments
yuliia-fryshko Jan 30, 2026
4ea551b
fixed check type
yuliia-fryshko Jan 30, 2026
8f6049e
fixed check type
yuliia-fryshko Jan 30, 2026
51a1ba8
Changes from node scripts/eslint_all_files --no-cache --fix
kibanamachine Jan 30, 2026
f2faa93
Merge branch 'main' into edit-log-insight-system-promt-445
yuliia-fryshko Jan 30, 2026
cac6cfc
Merge branch 'main' into edit-log-insight-system-promt-445
yuliia-fryshko Feb 2, 2026
430b890
Update x-pack/solutions/observability/plugins/observability_agent_bui…
yuliia-fryshko Feb 2, 2026
a3a965b
Update x-pack/solutions/observability/plugins/observability_agent_bui…
yuliia-fryshko Feb 2, 2026
6500993
Update x-pack/solutions/observability/plugins/observability_agent_bui…
yuliia-fryshko Feb 2, 2026
999af77
fixed review comment
yuliia-fryshko Feb 2, 2026
bbce724
fixed type check
yuliia-fryshko Feb 2, 2026
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 @@ -54,7 +54,7 @@ export function registerDataProviders({
logger,
arguments: {
'service.name': serviceName,
'service.environment': serviceEnvironment,
'service.environment': serviceEnvironment ? serviceEnvironment : ENVIRONMENT_ALL.value,
Comment thread
jennypavlova marked this conversation as resolved.
Outdated
start,
end,
'transaction.type': transactionType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,19 @@
*/
import moment from 'moment';
import { MessageRole, type InferenceClient } from '@kbn/inference-common';
import type { IScopedClusterClient, KibanaRequest } from '@kbn/core/server';
import type { IScopedClusterClient, KibanaRequest, CoreSetup, Logger } from '@kbn/core/server';
import { safeJsonStringify } from '@kbn/std';
import dedent from 'dedent';
import type { ObservabilityAgentBuilderDataRegistry } from '../../data_registry/data_registry';
import { getLogDocumentById } from './get_log_document_by_id';
import type {
ObservabilityAgentBuilderPluginSetupDependencies,
ObservabilityAgentBuilderPluginStart,
ObservabilityAgentBuilderPluginStartDependencies,
} from '../../types';
import { getApmIndices } from '../../utils/get_apm_indices';
import { fetchDistributedTrace } from './apm_error/fetch_distributed_trace';
import { parseDatemath } from '../../utils/time';

export interface GetLogAiInsightsParams {
index: string;
Expand All @@ -20,6 +28,12 @@ export interface GetLogAiInsightsParams {
connectorId: string;
request: KibanaRequest;
esClient: IScopedClusterClient;
core: CoreSetup<
ObservabilityAgentBuilderPluginStartDependencies,
ObservabilityAgentBuilderPluginStart
>;
Comment thread
yuliia-fryshko marked this conversation as resolved.
Outdated
plugins: ObservabilityAgentBuilderPluginSetupDependencies;
logger: Logger;
}

export async function getLogAiInsights({
Expand All @@ -30,10 +44,44 @@ export async function getLogAiInsights({
dataRegistry,
inferenceClient,
connectorId,
core,
plugins,
logger,
}: GetLogAiInsightsParams): Promise<{ summary: string; context: string }> {
const systemPrompt = dedent(`
You are assisting an SRE who is viewing a log entry in the Kibana Logs UI.
Using the provided data produce a concise, action-oriented response.`);
You are an expert SRE assistant helping a user analyze a log entry in Kibana. Your goal is to provide actionable insights tailored to the log's severity and content.

## Analysis Approach

1. **Classify the log by log.level**: Determine the log level from the log.level field (error, warning, info, debug, trace, fatal, critical, alert, emergency).
**Important**: Even if log.level is "info", "debug", or "trace", if the log mentions error messages, error fields, or exception fields, treat it as an error-level log.

2. **Respond based on log level:**

### Error/Fatal/Critical/Alert/Emergency Logs (or logs with error/exception fields)
Provide a thorough investigation:
- **What happened**: Summarize the error in plain language
- **Where it originated**: Identify the service, component, or code path
- **Root cause**: Analyze using ServiceSummary, DownstreamDependencies, TraceDocuments, and TraceServices if available
- **Impact**: Note any affected downstream services or dependencies
- **Next steps**: Suggest specific actions for investigation or remediation

### Warning Logs
- Assess whether the warning indicates an emerging problem or is purely informational
- If it signals a potential issue, analyze it like an error log (see above)
- If it's routine, provide a brief explanation of what triggered it

### Info/Debug/Trace Logs
Keep it concise:
- Explain what the log message means in context
- Identify the source (service, host, container)
- Only flag concerns if the content unexpectedly suggests a problem

## Important Notes
- Base your analysis strictly on the provided data (**DO NOT** speculate beyond what the evidence shows)
- Be specific: reference actual field values, timestamps, and service names from the log entry
- Prioritize actionable information over generic advice

@sorenlouv sorenlouv Jan 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a lot of text (tokens) talking about what seems like the same thing. Can you reduce it?

Also there is no need to say if log.level is "info" when we know the log.level:

if(logEntry.level === "info") {
 systemPrompt = 'This log is an info log...'
}

Btw: log.level is ECS-only. For otel it is severity_text / severity_number.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, @sorenlouv. I’ve added logic to distinguish log levels and updated the system prompt based on that.

`);

const logEntry = await getLogDocumentById({
esClient: esClient.asCurrentUser,
Expand All @@ -45,6 +93,14 @@ export async function getLogAiInsights({
throw new Error('Log entry not found');
}

const resourceAttributes = logEntry.resource?.attributes;

const serviceName =
logEntry.service?.name ?? (resourceAttributes?.['service.name'] as string) ?? '';

const serviceEnvironment =
logEntry.service?.environment ?? (resourceAttributes?.['service.environment'] as string) ?? '';

let context = dedent(`
<LogEntryIndex>
${index}
Expand All @@ -59,33 +115,119 @@ export async function getLogAiInsights({
</LogEntryFields>
`);

if (logEntry.service?.name && logEntry.service?.environment) {
const serviceSummary = await dataRegistry.getData('apmServiceSummary', {
request,
serviceName: logEntry.service?.name,
serviceEnvironment: logEntry.service?.environment,
start: moment(logEntry['@timestamp']).subtract(24, 'hours').toISOString(),
end: moment(logEntry['@timestamp']).add(24, 'hours').toISOString(),
if (serviceName) {
const logTimestamp = logEntry['@timestamp'] as string;
const start = moment(logTimestamp).subtract(24, 'hours').toISOString();
const end = moment(logTimestamp).add(24, 'hours').toISOString();

interface ContextPart {
name: string;
handler: () => Promise<unknown>;
}

const contextParts: ContextPart[] = [
{
name: 'ServiceSummary',
handler: () =>
dataRegistry.getData('apmServiceSummary', {
request,
serviceName,
serviceEnvironment,
start,
end,
}),
},
{
name: 'DownstreamDependencies',
handler: () =>
dataRegistry.getData('apmDownstreamDependencies', {
request,
serviceName,
serviceEnvironment,
start,
end,
}),
},
];

const traceId = (logEntry.trace_id as string) || (logEntry.trace as { id?: string })?.id;

if (traceId) {
const parsedStart = parseDatemath(start, { roundUp: false });
const parsedEnd = parseDatemath(end, { roundUp: true });
const traceContextPromise = (async () => {
const apmIndices = await getApmIndices({ core, plugins, logger });
return fetchDistributedTrace({
esClient,
apmIndices,
traceId,
start: parsedStart,
end: parsedEnd,
logger,
});
})();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: IIFE's is a somewhat confusing pattern. I think readability will improve with

Suggested change
const traceContextPromise = (async () => {
const apmIndices = await getApmIndices({ core, plugins, logger });
return fetchDistributedTrace({
esClient,
apmIndices,
traceId,
start: parsedStart,
end: parsedEnd,
logger,
});
})();
const traceDocumentsPromise = getApmIndices({ core, plugins, logger }).then((apmIndices) => {
return fetchDistributedTrace({
esClient,
apmIndices,
traceId,
start: parsedStart,
end: parsedEnd,
logger,
});
})


contextParts.push({
name: 'TraceDocuments',
handler: async () => (await traceContextPromise).traceDocuments,
Comment thread
viduni94 marked this conversation as resolved.
Outdated
});

contextParts.push({
name: 'TraceServices',
handler: async () => (await traceContextPromise).services,
});
}

const results = await Promise.allSettled(
contextParts.map(async (part) => {
const data = await part.handler();
return { part, data };
})
);

const contextPartsStrings: string[] = [];

results.forEach((result) => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can you use map and filter to keep it immutable.

if (result.status === 'rejected') {
logger.debug(`Log AI Insight: fetch failed: ${result.reason}`);
return;
}

const { part, data } = result.value;
if (!data || (Array.isArray(data) && data.length === 0)) {
return;
}

contextPartsStrings.push(
dedent(`
<${part.name}>
Time window: ${start} to ${end}
\`\`\`json
${safeJsonStringify(data)}
\`\`\`
</${part.name}>
`)
);
});
context += dedent(`
<ServiceSummary>
\`\`\`json
${safeJsonStringify(serviceSummary)}
\`\`\`
</ServiceSummary>
`);
}

if (contextPartsStrings.length > 0) {
context += contextPartsStrings.join('\n\n');
}
}
const response = await inferenceClient.chatComplete({
connectorId,
system: systemPrompt,
messages: [
{
role: MessageRole.User,
content:
dedent(`Explain this log message: what it means, where it is from, whether it is expected, and if it is an issue.
content: dedent(`
<LogContext>
${context}
`),
</LogContext>
Analyze this log entry and generate a summary explaining what it means, whether this is expected behavior or indicates an issue (e.g., error, warning, exception, service failure, etc.).
If it indicates an issue, explain the likely root cause if determinable and recommended actions or steps for further investigation.
Follow your system instructions. Ensure the analysis is grounded in the provided context, and concise.

@sorenlouv sorenlouv Jan 26, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does "Follow your system instructions" have an effect?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, I don't think it's very needed

`),
},
],
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ export interface LogDocument {
name?: string;
environment?: string;
};
resource?: {
attributes?: Record<string, unknown>;
};
[key: string]: unknown;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export function getObservabilityAgentBuilderAiInsightsRouteRepository() {
id: t.string,
}),
}),
handler: async ({ request, core, dataRegistry, params }) => {
handler: async ({ request, core, dataRegistry, params, logger, plugins }) => {
const { index, id } = params.body;

const [coreStart, startDeps] = await core.getStartServices();
Expand All @@ -146,6 +146,9 @@ export function getObservabilityAgentBuilderAiInsightsRouteRepository() {
request,
esClient,
dataRegistry,
core,
plugins,
logger,
});

return { summary, context };
Expand Down