mirror of
https://github.com/sourcebot-dev/sourcebot.git
synced 2025-12-13 12:55:19 +00:00
Add back posthog search_finished event
This commit is contained in:
parent
9c9b6b9578
commit
d55dd13c1b
3 changed files with 79 additions and 44 deletions
|
|
@ -32,6 +32,7 @@ import { CodePreviewPanel } from "./codePreviewPanel";
|
||||||
import { FilterPanel } from "./filterPanel";
|
import { FilterPanel } from "./filterPanel";
|
||||||
import { useFilteredMatches } from "./filterPanel/useFilterMatches";
|
import { useFilteredMatches } from "./filterPanel/useFilterMatches";
|
||||||
import { SearchResultsPanel, SearchResultsPanelHandle } from "./searchResultsPanel";
|
import { SearchResultsPanel, SearchResultsPanelHandle } from "./searchResultsPanel";
|
||||||
|
import useCaptureEvent from "@/hooks/useCaptureEvent";
|
||||||
|
|
||||||
interface SearchResultsPageProps {
|
interface SearchResultsPageProps {
|
||||||
searchQuery: string;
|
searchQuery: string;
|
||||||
|
|
@ -50,6 +51,7 @@ export const SearchResultsPage = ({
|
||||||
const { setSearchHistory } = useSearchHistory();
|
const { setSearchHistory } = useSearchHistory();
|
||||||
const domain = useDomain();
|
const domain = useDomain();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
|
const captureEvent = useCaptureEvent();
|
||||||
|
|
||||||
// Encodes the number of matches to return in the search response.
|
// Encodes the number of matches to return in the search response.
|
||||||
const _maxMatchCount = parseInt(useNonEmptyQueryParam(SearchQueryParams.matches) ?? `${defaultMaxMatchCount}`);
|
const _maxMatchCount = parseInt(useNonEmptyQueryParam(SearchQueryParams.matches) ?? `${defaultMaxMatchCount}`);
|
||||||
|
|
@ -59,7 +61,8 @@ export const SearchResultsPage = ({
|
||||||
error,
|
error,
|
||||||
files,
|
files,
|
||||||
repoInfo,
|
repoInfo,
|
||||||
durationMs,
|
timeToSearchCompletionMs,
|
||||||
|
timeToFirstSearchResultMs,
|
||||||
isStreaming,
|
isStreaming,
|
||||||
numMatches,
|
numMatches,
|
||||||
isExhaustive,
|
isExhaustive,
|
||||||
|
|
@ -98,40 +101,52 @@ export const SearchResultsPage = ({
|
||||||
])
|
])
|
||||||
}, [searchQuery, setSearchHistory]);
|
}, [searchQuery, setSearchHistory]);
|
||||||
|
|
||||||
// @todo: capture search stats on completion.
|
useEffect(() => {
|
||||||
// useEffect(() => {
|
if (isStreaming || !stats) {
|
||||||
// if (!searchResponse) {
|
return;
|
||||||
// return;
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
// const fileLanguages = searchResponse.files?.map(file => file.language) || [];
|
const fileLanguages = files.map(file => file.language) || [];
|
||||||
|
|
||||||
// captureEvent("search_finished", {
|
console.debug('timeToFirstSearchResultMs:', timeToFirstSearchResultMs);
|
||||||
// durationMs: searchResponse.totalClientSearchDurationMs,
|
console.debug('timeToSearchCompletionMs:', timeToSearchCompletionMs);
|
||||||
// fileCount: searchResponse.stats.fileCount,
|
|
||||||
// matchCount: searchResponse.stats.totalMatchCount,
|
|
||||||
// actualMatchCount: searchResponse.stats.actualMatchCount,
|
|
||||||
// filesSkipped: searchResponse.stats.filesSkipped,
|
|
||||||
// contentBytesLoaded: searchResponse.stats.contentBytesLoaded,
|
|
||||||
// indexBytesLoaded: searchResponse.stats.indexBytesLoaded,
|
|
||||||
// crashes: searchResponse.stats.crashes,
|
|
||||||
// shardFilesConsidered: searchResponse.stats.shardFilesConsidered,
|
|
||||||
// filesConsidered: searchResponse.stats.filesConsidered,
|
|
||||||
// filesLoaded: searchResponse.stats.filesLoaded,
|
|
||||||
// shardsScanned: searchResponse.stats.shardsScanned,
|
|
||||||
// shardsSkipped: searchResponse.stats.shardsSkipped,
|
|
||||||
// shardsSkippedFilter: searchResponse.stats.shardsSkippedFilter,
|
|
||||||
// ngramMatches: searchResponse.stats.ngramMatches,
|
|
||||||
// ngramLookups: searchResponse.stats.ngramLookups,
|
|
||||||
// wait: searchResponse.stats.wait,
|
|
||||||
// matchTreeConstruction: searchResponse.stats.matchTreeConstruction,
|
|
||||||
// matchTreeSearch: searchResponse.stats.matchTreeSearch,
|
|
||||||
// regexpsConsidered: searchResponse.stats.regexpsConsidered,
|
|
||||||
// flushReason: searchResponse.stats.flushReason,
|
|
||||||
// fileLanguages,
|
|
||||||
// });
|
|
||||||
// }, [captureEvent, searchQuery, searchResponse]);
|
|
||||||
|
|
||||||
|
captureEvent("search_finished", {
|
||||||
|
durationMs: timeToSearchCompletionMs,
|
||||||
|
timeToSearchCompletionMs,
|
||||||
|
timeToFirstSearchResultMs,
|
||||||
|
fileCount: stats.fileCount,
|
||||||
|
matchCount: stats.totalMatchCount,
|
||||||
|
actualMatchCount: stats.actualMatchCount,
|
||||||
|
filesSkipped: stats.filesSkipped,
|
||||||
|
contentBytesLoaded: stats.contentBytesLoaded,
|
||||||
|
indexBytesLoaded: stats.indexBytesLoaded,
|
||||||
|
crashes: stats.crashes,
|
||||||
|
shardFilesConsidered: stats.shardFilesConsidered,
|
||||||
|
filesConsidered: stats.filesConsidered,
|
||||||
|
filesLoaded: stats.filesLoaded,
|
||||||
|
shardsScanned: stats.shardsScanned,
|
||||||
|
shardsSkipped: stats.shardsSkipped,
|
||||||
|
shardsSkippedFilter: stats.shardsSkippedFilter,
|
||||||
|
ngramMatches: stats.ngramMatches,
|
||||||
|
ngramLookups: stats.ngramLookups,
|
||||||
|
wait: stats.wait,
|
||||||
|
matchTreeConstruction: stats.matchTreeConstruction,
|
||||||
|
matchTreeSearch: stats.matchTreeSearch,
|
||||||
|
regexpsConsidered: stats.regexpsConsidered,
|
||||||
|
flushReason: stats.flushReason,
|
||||||
|
fileLanguages,
|
||||||
|
isSearchExhaustive: isExhaustive,
|
||||||
|
});
|
||||||
|
}, [
|
||||||
|
captureEvent,
|
||||||
|
files,
|
||||||
|
isStreaming,
|
||||||
|
isExhaustive,
|
||||||
|
stats,
|
||||||
|
timeToSearchCompletionMs,
|
||||||
|
timeToFirstSearchResultMs,
|
||||||
|
]);
|
||||||
|
|
||||||
const onLoadMoreResults = useCallback(() => {
|
const onLoadMoreResults = useCallback(() => {
|
||||||
const url = createPathWithQueryParams(`/${domain}/search`,
|
const url = createPathWithQueryParams(`/${domain}/search`,
|
||||||
|
|
@ -170,7 +185,7 @@ export const SearchResultsPage = ({
|
||||||
onLoadMoreResults={onLoadMoreResults}
|
onLoadMoreResults={onLoadMoreResults}
|
||||||
numMatches={numMatches}
|
numMatches={numMatches}
|
||||||
repoInfo={repoInfo}
|
repoInfo={repoInfo}
|
||||||
searchDurationMs={durationMs}
|
searchDurationMs={timeToSearchCompletionMs}
|
||||||
isStreaming={isStreaming}
|
isStreaming={isStreaming}
|
||||||
searchStats={stats}
|
searchStats={stats}
|
||||||
isMoreResultsButtonVisible={!isExhaustive}
|
isMoreResultsButtonVisible={!isExhaustive}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,8 @@ interface CacheEntry {
|
||||||
files: SearchResultFile[];
|
files: SearchResultFile[];
|
||||||
repoInfo: Record<number, RepositoryInfo>;
|
repoInfo: Record<number, RepositoryInfo>;
|
||||||
numMatches: number;
|
numMatches: number;
|
||||||
durationMs: number;
|
timeToSearchCompletionMs: number;
|
||||||
|
timeToFirstSearchResultMs: number;
|
||||||
timestamp: number;
|
timestamp: number;
|
||||||
isExhaustive: boolean;
|
isExhaustive: boolean;
|
||||||
}
|
}
|
||||||
|
|
@ -39,7 +40,8 @@ export const useStreamedSearch = ({ query, matches, contextLines, whole, isRegex
|
||||||
error: Error | null,
|
error: Error | null,
|
||||||
files: SearchResultFile[],
|
files: SearchResultFile[],
|
||||||
repoInfo: Record<number, RepositoryInfo>,
|
repoInfo: Record<number, RepositoryInfo>,
|
||||||
durationMs: number,
|
timeToSearchCompletionMs: number,
|
||||||
|
timeToFirstSearchResultMs: number,
|
||||||
numMatches: number,
|
numMatches: number,
|
||||||
stats?: SearchStats,
|
stats?: SearchStats,
|
||||||
}>({
|
}>({
|
||||||
|
|
@ -48,7 +50,8 @@ export const useStreamedSearch = ({ query, matches, contextLines, whole, isRegex
|
||||||
error: null,
|
error: null,
|
||||||
files: [],
|
files: [],
|
||||||
repoInfo: {},
|
repoInfo: {},
|
||||||
durationMs: 0,
|
timeToSearchCompletionMs: 0,
|
||||||
|
timeToFirstSearchResultMs: 0,
|
||||||
numMatches: 0,
|
numMatches: 0,
|
||||||
stats: undefined,
|
stats: undefined,
|
||||||
});
|
});
|
||||||
|
|
@ -94,7 +97,8 @@ export const useStreamedSearch = ({ query, matches, contextLines, whole, isRegex
|
||||||
error: null,
|
error: null,
|
||||||
files: cachedEntry.files,
|
files: cachedEntry.files,
|
||||||
repoInfo: cachedEntry.repoInfo,
|
repoInfo: cachedEntry.repoInfo,
|
||||||
durationMs: cachedEntry.durationMs,
|
timeToSearchCompletionMs: cachedEntry.timeToSearchCompletionMs,
|
||||||
|
timeToFirstSearchResultMs: cachedEntry.timeToFirstSearchResultMs,
|
||||||
numMatches: cachedEntry.numMatches,
|
numMatches: cachedEntry.numMatches,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
|
@ -106,7 +110,8 @@ export const useStreamedSearch = ({ query, matches, contextLines, whole, isRegex
|
||||||
error: null,
|
error: null,
|
||||||
files: [],
|
files: [],
|
||||||
repoInfo: {},
|
repoInfo: {},
|
||||||
durationMs: 0,
|
timeToSearchCompletionMs: 0,
|
||||||
|
timeToFirstSearchResultMs: 0,
|
||||||
numMatches: 0,
|
numMatches: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -138,6 +143,7 @@ export const useStreamedSearch = ({ query, matches, contextLines, whole, isRegex
|
||||||
const reader = response.body.getReader();
|
const reader = response.body.getReader();
|
||||||
const decoder = new TextDecoder();
|
const decoder = new TextDecoder();
|
||||||
let buffer = '';
|
let buffer = '';
|
||||||
|
let numMessagesProcessed = 0;
|
||||||
|
|
||||||
while (true as boolean) {
|
while (true as boolean) {
|
||||||
const { done, value } = await reader.read();
|
const { done, value } = await reader.read();
|
||||||
|
|
@ -175,6 +181,7 @@ export const useStreamedSearch = ({ query, matches, contextLines, whole, isRegex
|
||||||
}
|
}
|
||||||
|
|
||||||
const response: StreamedSearchResponse = JSON.parse(data);
|
const response: StreamedSearchResponse = JSON.parse(data);
|
||||||
|
const isFirstMessage = numMessagesProcessed === 0;
|
||||||
switch (response.type) {
|
switch (response.type) {
|
||||||
case 'chunk':
|
case 'chunk':
|
||||||
setState(prev => ({
|
setState(prev => ({
|
||||||
|
|
@ -191,6 +198,9 @@ export const useStreamedSearch = ({ query, matches, contextLines, whole, isRegex
|
||||||
}, {} as Record<number, RepositoryInfo>),
|
}, {} as Record<number, RepositoryInfo>),
|
||||||
},
|
},
|
||||||
numMatches: prev.numMatches + response.stats.actualMatchCount,
|
numMatches: prev.numMatches + response.stats.actualMatchCount,
|
||||||
|
...(isFirstMessage ? {
|
||||||
|
timeToFirstSearchResultMs: performance.now() - startTime,
|
||||||
|
} : {}),
|
||||||
}));
|
}));
|
||||||
break;
|
break;
|
||||||
case 'final':
|
case 'final':
|
||||||
|
|
@ -198,13 +208,18 @@ export const useStreamedSearch = ({ query, matches, contextLines, whole, isRegex
|
||||||
...prev,
|
...prev,
|
||||||
isExhaustive: response.isSearchExhaustive,
|
isExhaustive: response.isSearchExhaustive,
|
||||||
stats: response.accumulatedStats,
|
stats: response.accumulatedStats,
|
||||||
|
...(isFirstMessage ? {
|
||||||
|
timeToFirstSearchResultMs: performance.now() - startTime,
|
||||||
|
} : {}),
|
||||||
}));
|
}));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
numMessagesProcessed++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const durationMs = performance.now() - startTime;
|
const timeToSearchCompletionMs = performance.now() - startTime;
|
||||||
setState(prev => {
|
setState(prev => {
|
||||||
// Cache the final results after the stream has completed.
|
// Cache the final results after the stream has completed.
|
||||||
searchCache.set(cacheKey, {
|
searchCache.set(cacheKey, {
|
||||||
|
|
@ -212,12 +227,13 @@ export const useStreamedSearch = ({ query, matches, contextLines, whole, isRegex
|
||||||
repoInfo: prev.repoInfo,
|
repoInfo: prev.repoInfo,
|
||||||
isExhaustive: prev.isExhaustive,
|
isExhaustive: prev.isExhaustive,
|
||||||
numMatches: prev.numMatches,
|
numMatches: prev.numMatches,
|
||||||
durationMs,
|
timeToFirstSearchResultMs: prev.timeToFirstSearchResultMs,
|
||||||
|
timeToSearchCompletionMs,
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
...prev,
|
...prev,
|
||||||
durationMs,
|
timeToSearchCompletionMs,
|
||||||
isStreaming: false,
|
isStreaming: false,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -229,11 +245,11 @@ export const useStreamedSearch = ({ query, matches, contextLines, whole, isRegex
|
||||||
|
|
||||||
console.error(error);
|
console.error(error);
|
||||||
Sentry.captureException(error);
|
Sentry.captureException(error);
|
||||||
const durationMs = performance.now() - startTime;
|
const timeToSearchCompletionMs = performance.now() - startTime;
|
||||||
setState(prev => ({
|
setState(prev => ({
|
||||||
...prev,
|
...prev,
|
||||||
isStreaming: false,
|
isStreaming: false,
|
||||||
durationMs,
|
timeToSearchCompletionMs,
|
||||||
error: error as Error,
|
error: error as Error,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,10 @@ export type PosthogEventMap = {
|
||||||
contentBytesLoaded: number,
|
contentBytesLoaded: number,
|
||||||
indexBytesLoaded: number,
|
indexBytesLoaded: number,
|
||||||
crashes: number,
|
crashes: number,
|
||||||
|
/** @deprecated: use timeToFirstSearchResultMs and timeToSearchCompletionMs instead */
|
||||||
durationMs: number,
|
durationMs: number,
|
||||||
|
timeToFirstSearchResultMs: number,
|
||||||
|
timeToSearchCompletionMs: number,
|
||||||
fileCount: number,
|
fileCount: number,
|
||||||
shardFilesConsidered: number,
|
shardFilesConsidered: number,
|
||||||
filesConsidered: number,
|
filesConsidered: number,
|
||||||
|
|
@ -23,7 +26,8 @@ export type PosthogEventMap = {
|
||||||
matchTreeSearch: number,
|
matchTreeSearch: number,
|
||||||
regexpsConsidered: number,
|
regexpsConsidered: number,
|
||||||
flushReason: number,
|
flushReason: number,
|
||||||
fileLanguages: string[]
|
fileLanguages: string[],
|
||||||
|
isSearchExhaustive: boolean
|
||||||
},
|
},
|
||||||
share_link_created: {},
|
share_link_created: {},
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue