useLogsQuery.tsx141 lines · main
1import { useQuery } from '@tanstack/react-query'
2import { IS_PLATFORM } from 'common'
3import { Dispatch, SetStateAction, useEffect, useState } from 'react'
4
5import {
6 EXPLORER_DATEPICKER_HELPERS,
7 getDefaultHelper,
8} from '@/components/interfaces/Settings/Logs/Logs.constants'
9import type {
10 LogData,
11 Logs,
12 LogsEndpointParams,
13} from '@/components/interfaces/Settings/Logs/Logs.types'
14import {
15 checkForILIKEClause,
16 checkForWithClause,
17} from '@/components/interfaces/Settings/Logs/Logs.utils'
18import { get } from '@/data/fetchers'
19import { logsAllEndpointUrl } from '@/data/logs/logs-endpoint'
20import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled'
21import { DOCS_URL } from '@/lib/constants'
22
23export interface LogsQueryHook {
24 params: LogsEndpointParams
25 isLoading: boolean
26 logData: LogData[]
27 data?: never
28 error: string | Object | null
29 changeQuery: (newQuery?: string) => void
30 runQuery: () => void
31 setParams: Dispatch<SetStateAction<LogsEndpointParams>>
32 enabled?: boolean
33}
34
35export const useLogsQuery = (
36 projectRef: string,
37 initialParams: Partial<LogsEndpointParams> = {},
38 enabled = true,
39 options: { useOtel?: boolean } = {}
40): LogsQueryHook => {
41 const { useOtel = false } = options
42 const defaultHelper = getDefaultHelper(EXPLORER_DATEPICKER_HELPERS)
43 const [params, setParams] = useState<LogsEndpointParams>({
44 sql: initialParams?.sql || '',
45 iso_timestamp_start: initialParams.iso_timestamp_start
46 ? initialParams.iso_timestamp_start
47 : defaultHelper.calcFrom(),
48 iso_timestamp_end: initialParams.iso_timestamp_end
49 ? initialParams.iso_timestamp_end
50 : defaultHelper.calcTo(),
51 })
52
53 const { logsMetadata } = useIsFeatureEnabled(['logs:metadata'])
54
55 useEffect(() => {
56 setParams((prev) => ({
57 ...prev,
58 ...initialParams,
59 sql: initialParams?.sql ?? prev.sql,
60 iso_timestamp_start: initialParams.iso_timestamp_start ?? prev.iso_timestamp_start,
61 iso_timestamp_end: initialParams.iso_timestamp_end ?? prev.iso_timestamp_end,
62 }))
63 }, [initialParams.sql, initialParams.iso_timestamp_start, initialParams.iso_timestamp_end])
64
65 const _enabled = enabled && typeof projectRef !== 'undefined' && Boolean(params.sql)
66
67 const usesWith = checkForWithClause(params.sql || '')
68 const usesILIKE = checkForILIKEClause(params.sql || '')
69
70 const {
71 data,
72 error: rqError,
73 isPending: isLoading,
74 isRefetching,
75 refetch,
76 } = useQuery({
77 queryKey: ['projects', projectRef, 'logs', params, { otel: useOtel }],
78 queryFn: async ({ signal }) => {
79 const { data, error } = await get(logsAllEndpointUrl(useOtel), {
80 params: {
81 path: { ref: projectRef },
82 query: params,
83 },
84 signal,
85 })
86 if (error) {
87 throw error
88 }
89
90 return data as unknown as Logs
91 },
92 enabled: _enabled,
93 refetchOnWindowFocus: false,
94 })
95
96 let error: null | string | object = rqError ? (rqError as any).message : null
97
98 if (!error && data?.error) {
99 error = data?.error
100 }
101
102 // BigQuery-specific parser limitations don't apply to the ClickHouse-backed
103 // OTEL endpoint, so skip these warnings when querying it.
104 if (IS_PLATFORM && !useOtel) {
105 if (usesWith) {
106 error = {
107 message: 'The parser does not yet support WITH and subquery statements.',
108 docs: `${DOCS_URL}/guides/platform/advanced-log-filtering#the-with-keyword-and-subqueries-are-not-supported`,
109 }
110 }
111 if (usesILIKE) {
112 error = {
113 message: 'BigQuery does not support ILIKE. Use REGEXP_CONTAINS instead.',
114 docs: `${DOCS_URL}/guides/platform/advanced-log-filtering#the-ilike-and-similar-to-keywords-are-not-supported`,
115 }
116 }
117 }
118 const changeQuery = (newQuery = '') => {
119 setParams((prev) => ({ ...prev, sql: newQuery }))
120 }
121
122 const logData = (data?.result ?? []).map((x) => {
123 if (logsMetadata) {
124 return x
125 } else {
126 const { metadata, ...log } = x
127 return log
128 }
129 })
130
131 return {
132 params,
133 isLoading: (_enabled && isLoading) || isRefetching,
134 logData: logData,
135 error,
136 changeQuery,
137 runQuery: () => refetch(),
138 setParams,
139 }
140}
141export default useLogsQuery