CloudWatch: Track Logs Insights query language (#100254)

Co-authored-by: Kevin Yu <kevinwcyu@users.noreply.github.com>
This commit is contained in:
Ida Štambuk 2025-02-10 18:13:26 +01:00 committed by GitHub
parent 0152f414f0
commit 4e48b7557c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 83 additions and 29 deletions

View File

@ -2,6 +2,21 @@ import { DashboardLoadedEvent } from '@grafana/data';
import { CloudWatchQuery } from '../types'; import { CloudWatchQuery } from '../types';
const baseLogsQuery = {
datasource: {
type: 'cloudwatch',
uid: 'P7DC3E4760CFAC4AP',
},
expression: 'fields @timestamp, @message | sort @timestamp desc | limit 300 ',
id: '',
logGroupNames: ['/aws/lambda/hello-world', '/aws/sagemaker/Endpoints/test', '/aws/sagemaker/test'],
namespace: '',
queryMode: 'Logs',
refId: 'A',
region: 'default',
statsGroups: [],
};
export const CloudWatchDashboardLoadedEvent = new DashboardLoadedEvent({ export const CloudWatchDashboardLoadedEvent = new DashboardLoadedEvent({
dashboardId: 'dashboard123', dashboardId: 'dashboard123',
orgId: 1, orgId: 1,
@ -460,18 +475,23 @@ export const CloudWatchDashboardLoadedEvent = new DashboardLoadedEvent({
statistic: 'Average', statistic: 'Average',
}, },
{ {
datasource: { ...baseLogsQuery,
type: 'cloudwatch',
uid: 'P7DC3E4760CFAC4AP',
}, },
expression: 'fields @timestamp, @message | sort @timestamp desc | limit 300 ', {
id: '', ...baseLogsQuery,
logGroupNames: ['/aws/lambda/hello-world', '/aws/sagemaker/Endpoints/test', '/aws/sagemaker/test'], queryLanguage: 'PPL',
namespace: '', },
queryMode: 'Logs', {
refId: 'A', ...baseLogsQuery,
region: 'default', queryLanguage: 'PPL',
statsGroups: [], },
{
...baseLogsQuery,
queryLanguage: 'SQL',
},
{
...baseLogsQuery,
queryLanguage: 'CWLI',
}, },
{ {
alias: '', alias: '',

View File

@ -6,10 +6,12 @@ import { GrafanaTheme2 } from '@grafana/data';
import { Collapse, useStyles2, Text } from '@grafana/ui'; import { Collapse, useStyles2, Text } from '@grafana/ui';
import { flattenTokens } from '@grafana/ui/src/slate-plugins/slate-prism'; import { flattenTokens } from '@grafana/ui/src/slate-plugins/slate-prism';
import { trackSampleQuerySelection } from '../../tracking';
import { CloudWatchLogsQuery, CloudWatchQuery, LogsQueryLanguage } from '../../types'; import { CloudWatchLogsQuery, CloudWatchQuery, LogsQueryLanguage } from '../../types';
import * as sampleQueries from './sampleQueries'; import * as sampleQueries from './sampleQueries';
import { cwliTokenizer, pplTokenizer, sqlTokenizer } from './tokenizer'; import { cwliTokenizer, pplTokenizer, sqlTokenizer } from './tokenizer';
interface QueryExample { interface QueryExample {
category: string; category: string;
examples: sampleQueries.SampleQuery[]; examples: sampleQueries.SampleQuery[];
@ -89,11 +91,26 @@ type Props = {
query: CloudWatchQuery; query: CloudWatchQuery;
}; };
const isLogsQuery = (query: CloudWatchQuery): query is CloudWatchLogsQuery => query.queryMode === 'Logs'; const isLogsQuery = (query: CloudWatchQuery): query is CloudWatchLogsQuery => query.queryMode === 'Logs';
const LogsCheatSheet = (props: Props) => { const LogsCheatSheet = (props: Props) => {
const styles = useStyles2(getStyles); const styles = useStyles2(getStyles);
const queryLanugage: LogsQueryLanguage = const queryLanguage: LogsQueryLanguage =
(isLogsQuery(props.query) && props.query.queryLanguage) || LogsQueryLanguage.CWLI; (isLogsQuery(props.query) && props.query.queryLanguage) || LogsQueryLanguage.CWLI;
const onClickExample = (query: sampleQueries.SampleQuery, queryCategory: string) => {
props.onClickExample({
...props.query,
refId: props.query.refId ?? 'A',
expression: query.expr[queryLanguage],
queryMode: 'Logs',
region: props.query.region,
id: props.query.refId ?? 'A',
logGroupNames: 'logGroupNames' in props.query ? props.query.logGroupNames : [],
logGroups: 'logGroups' in props.query ? props.query.logGroups : [],
});
trackSampleQuerySelection({ queryLanguage, queryCategory });
};
return ( return (
<div> <div>
<div className={styles.heading}> <div className={styles.heading}>
@ -106,7 +123,7 @@ const LogsCheatSheet = (props: Props) => {
<div key={`cat-${i}`}> <div key={`cat-${i}`}>
{query.examples.map((item, j) => ( {query.examples.map((item, j) => (
<> <>
{item.expr[queryLanugage] && ( {item.expr[queryLanguage] && (
<> <>
<Text variant="h6" weight="bold"> <Text variant="h6" weight="bold">
{item.title} {item.title}
@ -114,21 +131,10 @@ const LogsCheatSheet = (props: Props) => {
<button <button
type="button" type="button"
className={styles.cheatSheetExample} className={styles.cheatSheetExample}
key={item.expr[queryLanugage]} key={item.expr[queryLanguage]}
onClick={() => onClick={() => onClickExample(item, query.category)}
props.onClickExample({
...props.query,
refId: props.query.refId ?? 'A',
expression: item.expr[queryLanugage],
queryMode: 'Logs',
region: props.query.region,
id: props.query.refId ?? 'A',
logGroupNames: 'logGroupNames' in props.query ? props.query.logGroupNames : [],
logGroups: 'logGroups' in props.query ? props.query.logGroups : [],
})
}
> >
<pre>{renderHighlightedMarkup(item.expr[queryLanugage], `item-${j}`, queryLanugage)}</pre> <pre>{renderHighlightedMarkup(item.expr[queryLanguage], `item-${j}`, queryLanguage)}</pre>
</button> </button>
</> </>
)} )}

View File

@ -27,7 +27,10 @@ describe('onDashboardLoadedHandler', () => {
dashboard_id: 'dashboard123', dashboard_id: 'dashboard123',
grafana_version: 'v9.0.0', grafana_version: 'v9.0.0',
org_id: 1, org_id: 1,
logs_queries_count: 1, logs_queries_count: 5,
logs_cwli_queries_count: 2,
logs_sql_queries_count: 1,
logs_ppl_queries_count: 2,
metrics_queries_count: 21, metrics_queries_count: 21,
metrics_query_builder_count: 3, metrics_query_builder_count: 3,
metrics_query_code_count: 4, metrics_query_code_count: 4,

View File

@ -8,6 +8,7 @@ import {
CloudWatchLogsQuery, CloudWatchLogsQuery,
CloudWatchMetricsQuery, CloudWatchMetricsQuery,
CloudWatchQuery, CloudWatchQuery,
LogsQueryLanguage,
MetricEditorMode, MetricEditorMode,
MetricQueryType, MetricQueryType,
} from './types'; } from './types';
@ -21,6 +22,15 @@ type CloudWatchOnDashboardLoadedTrackingEvent = {
/* The number of CloudWatch logs queries present in the dashboard*/ /* The number of CloudWatch logs queries present in the dashboard*/
logs_queries_count: number; logs_queries_count: number;
/* The number of Logs queries that use Logs Insights query language */
logs_cwli_queries_count: number;
/* The number of Logs queries that use SQL language */
logs_sql_queries_count: number;
/* The number of Logs queries that use PPL language */
logs_ppl_queries_count: number;
/* The number of CloudWatch metrics queries present in the dashboard*/ /* The number of CloudWatch metrics queries present in the dashboard*/
metrics_queries_count: number; metrics_queries_count: number;
@ -88,6 +98,11 @@ export const onDashboardLoadedHandler = ({
dashboard_id: dashboardId, dashboard_id: dashboardId,
org_id: orgId, org_id: orgId,
logs_queries_count: logsQueries?.length, logs_queries_count: logsQueries?.length,
logs_cwli_queries_count: logsQueries?.filter(
(q) => !q.queryLanguage || q.queryLanguage === LogsQueryLanguage.CWLI
).length,
logs_sql_queries_count: logsQueries?.filter((q) => q.queryLanguage === LogsQueryLanguage.SQL).length,
logs_ppl_queries_count: logsQueries?.filter((q) => q.queryLanguage === LogsQueryLanguage.PPL).length,
metrics_queries_count: metricsQueries?.length, metrics_queries_count: metricsQueries?.length,
metrics_search_count: 0, metrics_search_count: 0,
metrics_search_builder_count: 0, metrics_search_builder_count: 0,
@ -124,5 +139,15 @@ export const onDashboardLoadedHandler = ({
} }
}; };
type SampleQueryTrackingEvent = {
queryLanguage: LogsQueryLanguage;
queryCategory: string;
};
export const trackSampleQuerySelection = (props: SampleQueryTrackingEvent) => {
const { queryLanguage, queryCategory } = props;
reportInteraction('cloudwatch-logs-cheat-sheet-query-clicked', { queryLanguage, queryCategory });
};
const isMetricSearchBuilder = (q: CloudWatchMetricsQuery) => const isMetricSearchBuilder = (q: CloudWatchMetricsQuery) =>
Boolean(q.metricQueryType === MetricQueryType.Search && q.metricEditorMode === MetricEditorMode.Builder); Boolean(q.metricQueryType === MetricQueryType.Search && q.metricEditorMode === MetricEditorMode.Builder);