Skip to main content
Glama
useLogs.ts3.28 kB
import { useState, useCallback } from 'react' import { useRequest, usePagination, useSSE } from 'alova/client' import { getLogHistory, getLogLevels, getRealtimeLogs } from '../api/logs' import type { LogEntry } from '../api/types' import type { DateRange } from 'react-day-picker' import { format } from 'date-fns' import { logger } from '@/utils/logger' /** * Hook for managing log history */ export const useLogHistory = (level?: string, search?: string, dateRange?: DateRange) => { const { from, to } = dateRange || {} const start_time = from ? format(from, 'yyyy-MM-dd') : undefined const end_time = to ? format(to, 'yyyy-MM-dd') : undefined const { data, page, pageSize, total, update, error } = usePagination( (page, pageSize) => getLogHistory({ page, page_size: pageSize, level, search, start_time, end_time, }), { initialData: { total: 0, data: [], }, initialPage: 1, initialPageSize: 20, watchingStates: [level, search, dateRange], data: (res) => res.items, total: (res) => res.total, } ) return { logs: data || [], total: total || 0, page: page || 1, pageSize: pageSize || 20, update, error, } } /** * Hook for getting log levels */ export const useLogLevels = () => { const { data: levelsData, loading: isLoading, error, } = useRequest(getLogLevels, { immediate: true, }) return { levels: levelsData?.levels || [], isLoading, error, } } /** * Hook for real-time log streaming */ export const useRealtimeLogs = (level?: string, search?: string) => { const [realtimeLogs, setRealtimeLogs] = useState<LogEntry[]>([]) // Create SSE connection using Alova const { eventSource, readyState, onMessage, onError, onOpen, send, close } = useSSE( () => getRealtimeLogs(level, search), { immediate: true, interceptByGlobalResponded: false, initialData: [], } ) // Handle incoming messages onMessage(({ data: messageData }) => { try { const logData = typeof messageData === 'string' ? JSON.parse(messageData) : messageData if (logData && !logData.error) { setRealtimeLogs((prev) => [...prev, logData].slice(-100)) // Keep only latest 100 logs } } catch (error) { logger.error('Failed to parse log event data:', error) } }) // Handle connection open onOpen(() => { logger.log('SSE connection opened') }) // Handle errors with auto-reconnect onError(({ error }) => { logger.error('SSE error:', error) // Auto reconnect after 3 seconds setTimeout(() => { if (readyState === 2) { // EventSource.CLOSED connect() } }, 3000) }) const connect = useCallback(() => { send() }, [send]) const disconnect = useCallback(() => { close() setRealtimeLogs([]) }, [close]) const clearLogs = useCallback(() => { setRealtimeLogs([]) }, []) return { realtimeLogs, isConnected: readyState === 1, // EventSource.OPEN connectionError: readyState === 2 ? 'Connection lost. Attempting to reconnect...' : null, readyState, eventSource, connect, disconnect, clearLogs, } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/itcook/graphiti-mcp-pro'

If you have feedback or need assistance with the MCP directory API, please join our Discord server