blob: 8a0f7ced0ad20f89c475a699c163cd87e96275be [file] [log] [blame]
# 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 asyncio
from collections import deque
import gradio as gr
from hugegraph_llm.config import admin_settings
from hugegraph_llm.utils.log import log
async def log_stream(log_path: str, lines: int = 125):
"""
Stream the content of a log file like `tail -f`.
"""
try:
with open(log_path, "r", encoding="utf-8") as file:
buffer = deque(file, maxlen=lines)
for line in buffer:
yield line # Yield the initial lines
while True:
line = file.readline()
if line:
yield line
else:
await asyncio.sleep(0.1) # Non-blocking sleep
except FileNotFoundError as exc:
raise Exception(f"Log file not found: {log_path}") from exc
except Exception as e:
raise Exception(f"An error occurred while reading the log: {str(e)}") from e
# Functions to read each log file
def read_llm_server_log(lines=250):
log_path = "logs/llm-server.log"
try:
with open(log_path, "r", encoding="utf-8", errors="replace") as f:
return "".join(deque(f, maxlen=lines))
except FileNotFoundError:
log.critical("Log file not found: %s", log_path)
return "LLM Server log file not found."
# Functions to clear each log file
def clear_llm_server_log():
log_path = "logs/llm-server.log"
try:
with open(log_path, "w", encoding="utf-8") as f:
f.truncate(0) # Clear the contents of the file
return "LLM Server log cleared."
except Exception as e: # pylint: disable=W0718
log.error("An error occurred while clearing the log: %s", str(e))
return "Failed to clear LLM Server log."
# Function to validate password and control access to logs
def check_password(password, request: gr.Request | None = None):
client_ip = request.client.host if request else "Unknown IP"
admin_token = admin_settings.admin_token
if password == admin_token:
# Return logs and update visibility
llm_log = read_llm_server_log()
# Log the successful access with the IP address
log.info("Logs accessed successfully from IP: %s", client_ip)
return (
llm_log,
gr.update(visible=True),
gr.update(visible=True),
gr.update(visible=True),
gr.update(visible=False),
)
# Log the failed attempt with IP address
log.error("Incorrect password attempt from IP: %s", client_ip)
return (
"",
gr.update(visible=False),
gr.update(visible=False),
gr.update(visible=False),
gr.update(value="Incorrect password. Access denied.", visible=True),
)
def create_admin_block():
with gr.Blocks():
gr.Markdown("## Admin Info - Password Protected")
# Password input
password_input = gr.Textbox(
label="Enter Password",
type="password",
placeholder="Enter password to access admin information",
)
# Error message box, initially hidden
error_message = gr.Textbox(
label="", visible=False, interactive=False, elem_classes="error-message"
)
# Button to submit password
submit_button = gr.Button("Submit")
with gr.Row(visible=False) as hidden_row:
with gr.Column():
# LLM Server log display, refreshes every 1 second
gr.Markdown("### LLM Server Log")
llm_server_log_output = gr.Code(
label="LLM Server Log (llm-server.log)",
lines=20,
value=f"```\n{read_llm_server_log()}\n```", # Initial value using the function
elem_classes="code-container-edit",
every=60, # Refresh every 60 second
)
with gr.Row():
with gr.Column():
# Button to clear LLM Server log, initially hidden
clear_llm_server_button = gr.Button("Clear LLM Server Log", visible=False)
with gr.Column():
# Button to refresh LLM Server log manually
refresh_llm_server_button = gr.Button(
"Refresh LLM Server Log", visible=False, variant="primary"
)
# Define what happens when the password is submitted
submit_button.click( # pylint: disable=E1101
fn=check_password,
inputs=[password_input],
outputs=[
llm_server_log_output,
hidden_row,
clear_llm_server_button,
refresh_llm_server_button,
error_message,
],
)
# Define what happens when the Clear LLM Server Log button is clicked
clear_llm_server_button.click( # pylint: disable=E1101
fn=clear_llm_server_log,
inputs=[],
outputs=[llm_server_log_output],
)
# Define what happens when the Refresh LLM Server Log button is clicked
refresh_llm_server_button.click( # pylint: disable=E1101
fn=read_llm_server_log,
inputs=[],
outputs=[llm_server_log_output],
)