blob: e12ea0db6d6502ea9929a8abef25b96f5d100d8d [file]
// 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 });
}