| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| |
| import { useQuery } from '@tanstack/react-query'; |
| |
| import { UiApiError } from './client'; |
| import { legacyGet, legacyPostFormMutation } from './operations'; |
| import type { UiLogSnapshot } from './types'; |
| |
| export const logQueryKey = ['ui', 'log'] as const; |
| |
| interface LegacyLogPayload { |
| LogConfiguration?: Record<string, unknown>; |
| LogContents?: Record<string, unknown>; |
| } |
| |
| function text(value: unknown): string { |
| if (value === null || value === undefined) return ''; |
| if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') return String(value); |
| return JSON.stringify(value); |
| } |
| |
| function names(value: unknown): string[] { |
| return text(value).split(',').map((name) => name.trim()).filter(Boolean); |
| } |
| |
| function logText(value: unknown): string { |
| return text(value).replace(/^<pre>/, '').replace(/<\/pre>$/, '').replace(/<\/br>/g, '\n'); |
| } |
| |
| export async function fetchLog(): Promise<UiLogSnapshot> { |
| const payload = await legacyGet<LegacyLogPayload>('/rest/v1/log'); |
| const configuration = payload.LogConfiguration ?? {}; |
| const contents = payload.LogContents ?? {}; |
| const showingLast = text(contents.showingLast); |
| return { |
| level: text(configuration.Level), |
| mode: text(configuration.Mode), |
| verboseNames: names(configuration.VerboseNames), |
| auditNames: names(configuration.AuditNames), |
| logPath: text(contents.logPath), |
| showingLastBytes: Number(showingLast.match(/\d+/)?.[0] ?? 0), |
| contents: contents.plainLog === undefined ? logText(contents.log) : text(contents.plainLog), |
| contentError: contents.error ? text(contents.error) : null, |
| }; |
| } |
| |
| export async function addVerboseName(name: string): Promise<void> { |
| await updateVerboseName('add_verbose', name); |
| } |
| |
| export async function deleteVerboseName(name: string): Promise<void> { |
| await updateVerboseName('del_verbose', name); |
| } |
| |
| async function updateVerboseName(parameter: 'add_verbose' | 'del_verbose', rawName: string): Promise<void> { |
| const name = rawName.trim(); |
| if (!/^[A-Za-z_$][A-Za-z0-9_$]*(\.[A-Za-z_$][A-Za-z0-9_$]*)*$/.test(name) || name.length > 256) { |
| throw new UiApiError(400, { |
| code: 'UI_LOG_VERBOSE_INVALID', |
| message: 'Enter a valid Java package or logger name (maximum 256 characters).', |
| requestId: 'client', |
| }); |
| } |
| await legacyPostFormMutation<Record<string, unknown>>( |
| '/rest/v1/log', new URLSearchParams({ [parameter]: name }), |
| ); |
| } |
| |
| export function useLog(enabled: boolean) { |
| return useQuery({ queryKey: logQueryKey, queryFn: fetchLog, enabled, refetchInterval: false }); |
| } |