Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ Table of Contents
- [Format](#format)
- [Modes](#modes)
- [The LLM (Claude) config file](#the-llm-claude-config-file)
- [Logging](#logging)
- [Log File Locations](#log-file-locations)
- [Log Features](#log-features)
- [Enabling File Logging](#enabling-file-logging)
- [Further Documentation](#further-documentation)
- [Additional Information](#additional-information)

Expand Down Expand Up @@ -227,6 +231,47 @@ And then add this section

This will pickup the default location of MCP server config file. It can also be passed in the `args` section above as `"--config-file", "<custom config file>"` after `run`

# Logging

The Dremio MCP server automatically writes log files to platform-specific directories following operating system conventions. This helps with troubleshooting and monitoring the server's operation.

## Log File Locations

The log files are stored in the following locations based on your operating system:

### Linux
- **Directory**: `~/.local/share/dremioai/logs/`
- **Full path**: `~/.local/share/dremioai/logs/dremioai.log`
- **XDG compliance**: Respects `$XDG_DATA_HOME` environment variable if set

### macOS
- **Directory**: `~/Library/Logs/dremioai/`
- **Full path**: `~/Library/Logs/dremioai/dremioai.log`

### Windows
- **Directory**: `%LOCALAPPDATA%\dremioai\logs\`
- **Full path**: `%LOCALAPPDATA%\dremioai\logs\dremioai.log`
- **Typical location**: `C:\Users\<username>\AppData\Local\dremioai\logs\dremioai.log`


## Controlling File Logging

By default, the MCP server logs to the logfile mentioned above. To control it further, you can use the following environment variables and command line options:

1. **Use JSON format**: `JSON_LOGGING=1` or pass `--enable-json-logging` for structured JSON logs
2. **Disable file logging**: pass `--no-log-to-file` to disable writing logs to file

Example:
```shell
$ uv run dremio-mcp-server run --no-log-to-file --enable-json-logging

# OR

$ uv run dremio-mcp-server run --enable-json-logging
```

The log directory is automatically created if it doesn't exist, so no manual setup is required.

# Further Documentation

1. [Architecture](docs/architecture.md): Detailed overview of the Dremio MCP server architecture, including component interactions and data flows.
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ dependencies = [
"langchain-ollama>=0.2.3",
"langchain-openai>=0.3.7",
"langgraph>=0.3.12",
"mcp>=1.3.0",
"mcp>=1.9.4",
"openai>=1.65.3",
"pandas>=2.2.3",
"prompt-toolkit>=3.0.50",
Expand Down
63 changes: 54 additions & 9 deletions src/dremioai/log.py
Original file line number Diff line number Diff line change
@@ -1,38 +1,69 @@
#
#
# Copyright (C) 2017-2025 Dremio Corporation
#
#
# Licensed 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 structlog
import logging
import os
import sys
from pathlib import Path
from logging.handlers import RotatingFileHandler
from logging import basicConfig


def get_log_directory(app_name: str = "dremioai") -> Path:
"""Get the appropriate log directory for the current platform."""
base_dir = None
match sys.platform:
case "win32":
base_dir = Path(
os.environ.get("LOCALAPPDATA", Path.home() / "AppData" / "Local")
)
base_dir = base_dir / app_name / "logs"
case "darwin":
base_dir = Path.home() / "Library" / "Logs" / app_name
case _:
base_dir = (
Path(os.environ.get("XDG_DATA_HOME", Path.home() / ".local" / "share"))
/ app_name
/ "logs"
)

if not base_dir.exists():
base_dir.mkdir(parents=True, exist_ok=True)
return base_dir


def get_log_file() -> Path:
return get_log_directory() / "dremioai.log"


def logger(name=None):
if not structlog.is_configured():
configure()
return structlog.get_logger(name)

basicConfig(level=logging.WARNING,
filename="/tmp/dremioai.log")

_level = None


def configure_file_logging(enable_json=False):
"""Convenience function to configure structlog with file logging enabled."""
configure(enable_json_logging=enable_json, to_file=True)


def level():
global _level
if _level is not None:
Expand All @@ -41,15 +72,29 @@ def level():


def set_level(l):
global _level
_level = l
# propagate to all loggers
logging.getLogger().setLevel(l)
for name in logging.getLogger().manager.loggerDict:
logging.getLogger().setLevel(l)
logging.getLogger(name).setLevel(l)


def configure(enable_json_logging=None, to_file=False):
if enable_json_logging is None:
enable_json_logging = "JSON_LOGGING" in os.environ

# Set up file logging if requested
if to_file:
log_file_path = get_log_file()

# Configure rotating file handler
file_handler = RotatingFileHandler(
log_file_path, maxBytes=10 * 1024 * 1024, backupCount=5 # 10MB
)
file_handler.setLevel(level())
logging.getLogger().addHandler(file_handler)

renderer = (
structlog.processors.JSONRenderer()
if enable_json_logging
Expand Down Expand Up @@ -81,4 +126,4 @@ def configure(enable_json_logging=None, to_file=False):
logger_factory=(structlog.stdlib.LoggerFactory()),
)

logging.getLogger().setLevel(level())
set_level(level())
13 changes: 7 additions & 6 deletions src/dremioai/servers/mcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,13 +105,13 @@ def main(
list_tools: Annotated[
bool, Option(help="List available tools for this mode and exit")
] = False,
log_to_file: Annotated[Optional[bool], Option(help="Log to file")] = False,
log_to_file: Annotated[Optional[bool], Option(help="Log to file")] = True,
enable_json_logging: Annotated[
Optional[bool], Option(help="Enable JSON logs")
] = False,
):
if not list_tools:
log.configure(enable_json_logging=True, to_file=True)
else:
log.configure(enable_json_logging=True, to_file=log_to_file)
log.set_level("DEBUG")
log.configure(enable_json_logging=enable_json_logging, to_file=log_to_file)
log.set_level("DEBUG")

if mode is not None:
mode = [tools.ToolType[m.upper()] for m in mode]
Expand Down Expand Up @@ -205,6 +205,7 @@ def show_default_config(
)
)
)
pp(f"Default log file: {log.get_log_file()!s}")
case ConfigTypes.claude:
cc = get_claude_config_path()
pp(f"Default config file: '{cc!s}' (exists = {cc.exists()!s})")
Expand Down
Loading