Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix circular dep and extra permission error in logs #436

Merged
merged 8 commits into from
Aug 3, 2020
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
62 changes: 37 additions & 25 deletions optimade/server/config.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# pylint: disable=no-self-argument
from enum import Enum
import json
import warnings
from typing import Optional, Dict, List

try:
Expand Down Expand Up @@ -41,8 +41,8 @@ class ServerConfig(BaseSettings):

"""

config_file: str = Field(
DEFAULT_CONFIG_FILE_PATH, description="File to load alternative defaults from",
config_file: Optional[str] = Field(
None, description="File to load alternative defaults from",
)
debug: bool = Field(
False, description="Turns on Debug Mode for the OPTIMADE Server implementation"
Expand Down Expand Up @@ -137,42 +137,54 @@ def set_implementation_version(cls, v):
res.update(v)
return res

@validator("log_level")
def force_debug_log_level(cls, v, values):
"""If `debug` is `True`, then force `log_level` to be `DEBUG` as well"""
from optimade.server.logger import CONSOLE_HANDLER

if values.get("debug", False):
v = LogLevel.DEBUG
CONSOLE_HANDLER.setLevel(v.value.upper())
return v

@root_validator(pre=True)
def load_default_settings(cls, values): # pylint: disable=no-self-argument
def load_settings(cls, values): # pylint: disable=no-self-argument
"""
Loads settings from a root file if available and uses that as defaults in
place of built in defaults
Loads settings from a JSON config file, if available, and uses them in place
of the built-in defaults.
"""
from optimade.server.logger import LOGGER

config_file_path = Path(values.get("config_file", DEFAULT_CONFIG_FILE_PATH))

new_values = {}

if config_file_path.exists() and config_file_path.is_file():
LOGGER.debug("Found config file at: %s", config_file_path)
with open(config_file_path) as f:
new_values = json.load(f)
if config_file_path.is_file():
try:
with open(config_file_path) as f:
new_values = json.load(f)
except json.JSONDecodeError as exc:
warnings.warn(
f"Unable to parse config file {config_file_path} as JSON. Error: {exc}."
)

else:
LOGGER.debug( # pragma: no cover
"Did not find config file at: %s", config_file_path
)
if DEFAULT_CONFIG_FILE_PATH != str(config_file_path):
warnings.warn(
f"Unable to find config file in requested location {config_file_path}, "
"using the built-in default settings instead."
)
else:
warnings.warn(
f"Unable to find config file in default location {DEFAULT_CONFIG_FILE_PATH}, "
"using the built-in default settings instead."
)

if not new_values:
new_values["config_file"] = None
ml-evs marked this conversation as resolved.
Show resolved Hide resolved
values["config_file"] = None

new_values.update(values)

return new_values

class Config:
"""
This is a pydantic model Config object that modifies the behaviour of
ServerConfig by adding a prefix to the environment variables that
override config file values. It has nothing to do with the OPTIMADE
config.

"""

env_prefix = "optimade_"


Expand Down
19 changes: 13 additions & 6 deletions optimade/server/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
from optimade.server.config import CONFIG

CONSOLE_HANDLER.setLevel(CONFIG.log_level.value.upper())

if CONFIG.debug:
CONSOLE_HANDLER.setLevel(logging.DEBUG)


except ImportError:
CONSOLE_HANDLER.setLevel(os.getenv("OPTIMADE_LOG_LEVEL", "INFO").upper())

Expand All @@ -37,23 +42,25 @@

try:
LOGS_DIR.mkdir(exist_ok=True)

# Handlers
FILE_HANDLER = logging.handlers.RotatingFileHandler(
LOGS_DIR.joinpath("optimade.log"), maxBytes=1000000, backupCount=5
)
CasperWA marked this conversation as resolved.
Show resolved Hide resolved

except OSError:
LOGGER.warning(
"""Log files are not saved.
f"""Log files are not saved.

This is usually due to not being able to access a specified log folder or write to files
in the specified log location, i.e., a `PermissionError` has been raised.

To solve this, either set the OPTIMADE_LOG_DIR environment variable to a location
you have permission to write to or create the /var/log/optimade folder, which is
you have permission to write to or create the {LOGS_DIR} folder, which is
the default logging folder, with write permissions for the Unix user running the server.
"""
)
else:
# Handlers
FILE_HANDLER = logging.handlers.RotatingFileHandler(
LOGS_DIR.joinpath("optimade.log"), maxBytes=1000000, backupCount=5
)
FILE_HANDLER.setLevel(logging.DEBUG)

# Formatter
Expand Down
19 changes: 16 additions & 3 deletions optimade/server/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,24 @@
This is an example implementation with example data.
To implement your own server see the documentation at https://optimade.org/optimade-python-tools.
"""

import warnings

from lark.exceptions import VisitError

from pydantic import ValidationError
from fastapi import FastAPI
from fastapi.exceptions import RequestValidationError, StarletteHTTPException
from fastapi.middleware.cors import CORSMiddleware

with warnings.catch_warnings(record=True) as w:
from optimade.server.config import CONFIG

config_warnings = w

from optimade import __api_version__, __version__
import optimade.server.exception_handlers as exc_handlers

from optimade.server.entry_collections import MongoCollection
from optimade.server.config import CONFIG
from optimade.server.logger import LOGGER
from optimade.server.middleware import (
AddWarnings,
Expand All @@ -35,10 +41,17 @@
from optimade.server.routers.utils import get_providers, BASE_URL_PREFIXES


if CONFIG.config_file is None:
LOGGER.warn(
f"Invalid config file or no config file provided, running server with default settings. Errors: "
f"{[warnings.formatwarning(w.message, w.category, w.filename, w.lineno, '') for w in config_warnings]}"
)
else:
LOGGER.info(f"Loaded settings from {CONFIG.config_file}.")

if CONFIG.debug: # pragma: no cover
LOGGER.info("DEBUG MODE")


app = FastAPI(
title="OPTIMADE API",
description=(
Expand Down
15 changes: 13 additions & 2 deletions optimade/server/main_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
To implement your own index meta-database server see the documentation at https://optimade.org/optimade-python-tools.
"""
import json
import warnings

from lark.exceptions import VisitError

Expand All @@ -14,10 +15,13 @@
from fastapi.exceptions import RequestValidationError, StarletteHTTPException
from fastapi.middleware.cors import CORSMiddleware

with warnings.catch_warnings(record=True) as w:
from optimade.server.config import CONFIG

config_warnings = w

from optimade import __api_version__, __version__
import optimade.server.exception_handlers as exc_handlers

from optimade.server.config import CONFIG
from optimade.server.logger import LOGGER
from optimade.server.middleware import (
AddWarnings,
Expand All @@ -28,6 +32,13 @@
from optimade.server.routers import index_info, links, versions
from optimade.server.routers.utils import BASE_URL_PREFIXES

if CONFIG.config_file is None:
LOGGER.warn(
f"Invalid config file or no config file provided, running server with default settings. Errors: "
f"{[warnings.formatwarning(w.message, w.category, w.filename, w.lineno, '') for w in config_warnings]}"
)
else:
LOGGER.info(f"Loaded settings from {CONFIG.config_file}.")

if CONFIG.debug: # pragma: no cover
LOGGER.info("DEBUG MODE")
Expand Down