Skip to content

Commit

Permalink
Use custom logger - phase 1
Browse files Browse the repository at this point in the history
  • Loading branch information
dormant-user committed Oct 1, 2024
1 parent 2914f05 commit 26305b1
Show file tree
Hide file tree
Showing 21 changed files with 126 additions and 49 deletions.
2 changes: 1 addition & 1 deletion docs/README.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="viewport" content="width=device-width, initial-scale=1" />

<title>PyNinja &#8212; PyNinja documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
Expand Down
12 changes: 10 additions & 2 deletions docs/genindex.html
Original file line number Diff line number Diff line change
Expand Up @@ -216,12 +216,14 @@ <h2 id="F">F</h2>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="index.html#pyninja.monitor.authenticator.failed_auth_counter">failed_auth_counter() (in module pyninja.monitor.authenticator)</a>
</li>
<li><a href="index.html#pyninja.modules.models.Session.forbid">forbid (pyninja.modules.models.Session attribute)</a>
<li><a href="index.html#pyninja.modules.models.LogOptions.file">file (pyninja.modules.models.LogOptions attribute)</a>
</li>
<li><a href="index.html#pyninja.executors.auth.forbidden">forbidden() (in module pyninja.executors.auth)</a>
<li><a href="index.html#pyninja.modules.models.Session.forbid">forbid (pyninja.modules.models.Session attribute)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="index.html#pyninja.executors.auth.forbidden">forbidden() (in module pyninja.executors.auth)</a>
</li>
<li><a href="index.html#pyninja.executors.squire.format_nos">format_nos() (in module pyninja.executors.squire)</a>
</li>
<li><a href="index.html#pyninja.executors.squire.format_timedelta">format_timedelta() (in module pyninja.executors.squire)</a>
Expand Down Expand Up @@ -397,10 +399,14 @@ <h2 id="L">L</h2>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="index.html#pyninja.executors.squire.load_env">load_env() (in module pyninja.executors.squire)</a>
</li>
<li><a href="index.html#pyninja.modules.models.EnvConfig.log">log (pyninja.modules.models.EnvConfig attribute)</a>
</li>
<li><a href="index.html#pyninja.modules.models.EnvConfig.log_config">log_config (pyninja.modules.models.EnvConfig attribute)</a>
</li>
<li><a href="index.html#pyninja.monitor.routes.login_endpoint">login_endpoint() (in module pyninja.monitor.routes)</a>
</li>
<li><a href="index.html#pyninja.modules.models.LogOptions">LogOptions (class in pyninja.modules.models)</a>
</li>
<li><a href="index.html#pyninja.monitor.routes.logout_endpoint">logout_endpoint() (in module pyninja.monitor.routes)</a>
</li>
Expand Down Expand Up @@ -734,6 +740,8 @@ <h2 id="S">S</h2>
<li><a href="index.html#pyninja.main.start">start() (in module pyninja.main)</a>
</li>
<li><a href="index.html#pyninja.modules.models.ServiceStatus.status_code">status_code (pyninja.modules.models.ServiceStatus attribute)</a>
</li>
<li><a href="index.html#pyninja.modules.models.LogOptions.stdout">stdout (pyninja.modules.models.LogOptions attribute)</a>
</li>
<li><a href="index.html#pyninja.features.service.stopped">stopped() (in module pyninja.features.service)</a>
</li>
Expand Down
26 changes: 25 additions & 1 deletion docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="viewport" content="width=device-width, initial-scale=1" />

<title>Welcome to PyNinja’s documentation! &#8212; PyNinja documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
Expand Down Expand Up @@ -1731,6 +1731,11 @@ <h2>Models<a class="headerlink" href="#models" title="Permalink to this heading"
<span class="sig-name descname"><span class="pre">log_config</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="pre">Optional</span><span class="p"><span class="pre">[</span></span><span class="pre">Union</span><span class="p"><span class="pre">[</span></span><span class="pre">Dict</span><span class="p"><span class="pre">[</span></span><span class="pre">str</span><span class="p"><span class="pre">,</span></span><span class="w"> </span><span class="pre">Any</span><span class="p"><span class="pre">]</span></span><span class="p"><span class="pre">,</span></span><span class="w"> </span><span class="pre">Path</span><span class="p"><span class="pre">]</span></span><span class="p"><span class="pre">]</span></span></em><a class="headerlink" href="#pyninja.modules.models.EnvConfig.log_config" title="Permalink to this definition"></a></dt>
<dd></dd></dl>

<dl class="py attribute">
<dt class="sig sig-object py" id="pyninja.modules.models.EnvConfig.log">
<span class="sig-name descname"><span class="pre">log</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><a class="reference internal" href="#pyninja.modules.models.LogOptions" title="pyninja.modules.models.LogOptions"><span class="pre">pyninja.modules.models.LogOptions</span></a><span class="w"> </span><span class="p"><span class="pre">|</span></span><span class="w"> </span><span class="pre">None</span></em><a class="headerlink" href="#pyninja.modules.models.EnvConfig.log" title="Permalink to this definition"></a></dt>
<dd></dd></dl>

<dl class="py method">
<dt class="sig sig-object py" id="pyninja.modules.models.EnvConfig.parse_api_secret">
<em class="property"><span class="pre">classmethod</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">parse_api_secret</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">value</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span><span class="w"> </span><span class="p"><span class="pre">|</span></span><span class="w"> </span><span class="pre">None</span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">str</span><span class="w"> </span><span class="p"><span class="pre">|</span></span><span class="w"> </span><span class="pre">None</span></span></span><a class="headerlink" href="#pyninja.modules.models.EnvConfig.parse_api_secret" title="Permalink to this definition"></a></dt>
Expand Down Expand Up @@ -1916,6 +1921,25 @@ <h2>Models<a class="headerlink" href="#models" title="Permalink to this heading"
</dl>
</dd></dl>

<dl class="py class">
<dt class="sig sig-object py" id="pyninja.modules.models.LogOptions">
<em class="property"><span class="pre">class</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">pyninja.modules.models.</span></span><span class="sig-name descname"><span class="pre">LogOptions</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">value</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">names</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="o"><span class="pre">*</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">module</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">qualname</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">type</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">start</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">1</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">boundary</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pyninja.modules.models.LogOptions" title="Permalink to this definition"></a></dt>
<dd><p>Log options for default log methods.</p>
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">LogOptions</span>
</pre></div>
</div>
<dl class="py attribute">
<dt class="sig sig-object py" id="pyninja.modules.models.LogOptions.stdout">
<span class="sig-name descname"><span class="pre">stdout</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="pre">str</span></em><em class="property"><span class="w"> </span><span class="p"><span class="pre">=</span></span><span class="w"> </span><span class="pre">'stdout'</span></em><a class="headerlink" href="#pyninja.modules.models.LogOptions.stdout" title="Permalink to this definition"></a></dt>
<dd></dd></dl>

<dl class="py attribute">
<dt class="sig sig-object py" id="pyninja.modules.models.LogOptions.file">
<span class="sig-name descname"><span class="pre">file</span></span><em class="property"><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="pre">str</span></em><em class="property"><span class="w"> </span><span class="p"><span class="pre">=</span></span><span class="w"> </span><span class="pre">'file'</span></em><a class="headerlink" href="#pyninja.modules.models.LogOptions.file" title="Permalink to this definition"></a></dt>
<dd></dd></dl>

</dd></dl>

<dl class="py class">
<dt class="sig sig-object py" id="pyninja.modules.models.Database">
<em class="property"><span class="pre">class</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">pyninja.modules.models.</span></span><span class="sig-name descname"><span class="pre">Database</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">datastore</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">Union</span><span class="p"><span class="pre">[</span></span><span class="pre">Path</span><span class="p"><span class="pre">,</span></span><span class="w"> </span><span class="pre">str</span><span class="p"><span class="pre">]</span></span></span></em>, <em class="sig-param"><span class="n"><span class="pre">timeout</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">10</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pyninja.modules.models.Database" title="Permalink to this definition"></a></dt>
Expand Down
Binary file modified docs/objects.inv
Binary file not shown.
2 changes: 1 addition & 1 deletion docs/searchindex.js

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions pyninja/executors/auth.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import logging
import secrets
import time
from datetime import datetime
Expand All @@ -8,9 +7,9 @@
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer

from pyninja.executors import database
from pyninja.logger import LOGGER
from pyninja.modules import exceptions, models

LOGGER = logging.getLogger("uvicorn.default")
EPOCH = lambda: int(time.time()) # noqa: E731
SECURITY = HTTPBearer()

Expand Down
3 changes: 1 addition & 2 deletions pyninja/executors/routes.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import logging
import shutil
import subprocess
from http import HTTPStatus
Expand All @@ -13,10 +12,10 @@

from pyninja.executors import auth, squire
from pyninja.features import cpu, disks, dockerized, operations, process, service
from pyninja.logger import LOGGER
from pyninja.modules import exceptions, models
from pyninja.monitor import resources

LOGGER = logging.getLogger("uvicorn.default")
BASIC_AUTH = HTTPBasic()
BEARER_AUTH = HTTPBearer()

Expand Down
3 changes: 1 addition & 2 deletions pyninja/executors/squire.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import json
import logging
import math
import os
import pathlib
Expand All @@ -14,9 +13,9 @@
import yaml
from pydantic import PositiveFloat, PositiveInt

from pyninja.logger import LOGGER
from pyninja.modules import models

LOGGER = logging.getLogger("uvicorn.default")
IP_REGEX = re.compile(
r"""^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$""" # noqa: E501
)
Expand Down
4 changes: 1 addition & 3 deletions pyninja/features/cpu.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import logging
import subprocess

from pydantic import FilePath

from pyninja.logger import LOGGER
from pyninja.modules import models

LOGGER = logging.getLogger("uvicorn.default")


def _darwin(lib_path: FilePath) -> str:
"""Get processor information for macOS.
Expand Down
4 changes: 1 addition & 3 deletions pyninja/features/disks.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import json
import logging
import re
import subprocess
from typing import Dict, List
Expand All @@ -8,10 +7,9 @@
from pydantic import FilePath

from pyninja.executors import squire
from pyninja.logger import LOGGER
from pyninja.modules import models

LOGGER = logging.getLogger("uvicorn.default")


def get_partitions_for_disk(device_id: str) -> List[str]:
"""Use psutil to find partitions for a given device.
Expand Down
3 changes: 1 addition & 2 deletions pyninja/features/dockerized.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import logging
from collections.abc import Generator
from typing import Dict, List

import docker
from docker.errors import DockerException

LOGGER = logging.getLogger("uvicorn.default")
from pyninja.logger import LOGGER


def get_container_status(name: str = None) -> str | None:
Expand Down
4 changes: 1 addition & 3 deletions pyninja/features/gpu.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import json
import logging
import subprocess
from typing import Dict, List, Optional

from pydantic import FilePath

from pyninja.logger import LOGGER
from pyninja.modules import models

LOGGER = logging.getLogger("uvicorn.default")


def _darwin(lib_path) -> Optional[List[Dict[str, str]]]:
"""Get GPU model and vendor information for Linux operating system.
Expand Down
4 changes: 1 addition & 3 deletions pyninja/features/operations.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import asyncio
import logging
import subprocess
import time
from datetime import timedelta
Expand All @@ -8,10 +7,9 @@
import psutil

from pyninja.executors import squire
from pyninja.logger import LOGGER
from pyninja.modules import models

LOGGER = logging.getLogger("uvicorn.default")


def default(name: str):
"""Default values for processes and services."""
Expand Down
4 changes: 1 addition & 3 deletions pyninja/features/process.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import logging
from concurrent.futures import as_completed
from typing import Dict, List

import psutil
from pydantic import PositiveInt

from pyninja.logger import LOGGER
from pyninja.modules import models

LOGGER = logging.getLogger("uvicorn.default")


def get_process_status(
process_name: str, cpu_interval: PositiveInt
Expand Down
4 changes: 1 addition & 3 deletions pyninja/features/service.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import logging
import subprocess
from http import HTTPStatus

from pyninja.logger import LOGGER
from pyninja.modules import models

LOGGER = logging.getLogger("uvicorn.default")


def running(service_name: str) -> models.ServiceStatus:
"""Constructs an ServiceStatus object with a status code.
Expand Down
50 changes: 50 additions & 0 deletions pyninja/logger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import importlib
import os
from datetime import datetime
import logging.config


def default_logger(log_to_file: bool) -> logging.Logger:
"""Generates a default console logger.
Args:
log_to_file: Boolean flag to stream logs to a file.
Returns:
logging.Logger:
Logger object.
"""
# todo: Use dictconfig instead of this ugliness
logging.getLogger("uvicorn.error").handlers = []
logging.getLogger("uvicorn.error").propagate = False

logging.getLogger("uvicorn.access").handlers = []
logging.getLogger("uvicorn.access").propagate = False

logging.getLogger("uvicorn.asgi").handlers = []
logging.getLogger("uvicorn.asgi").propagate = False

logging.getLogger("uvicorn.default").handlers = []
logging.getLogger("uvicorn.default").propagate = False

if log_to_file:
if not os.path.isdir("logs"):
os.mkdir("logs")
logfile: str = datetime.now().strftime(
os.path.join("logs", "pyninja_%d-%m-%Y.log")
)
handler = logging.FileHandler(filename=logfile)
else:
handler = logging.StreamHandler()
logger = logging.getLogger(__name__)
logger.setLevel(level=logging.INFO)
handler.setFormatter(
fmt=logging.Formatter(
fmt="%(asctime)s - %(levelname)-8s - [%(funcName)s:%(lineno)d] - %(message)s"
)
)
logger.addHandler(hdlr=handler)
return logger


LOGGER: logging.getLogger = None
23 changes: 13 additions & 10 deletions pyninja/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,11 @@
from fastapi.responses import JSONResponse, RedirectResponse
from fastapi.routing import APIRoute

from pyninja import version
from pyninja import logger, version
from pyninja.executors import routes, squire
from pyninja.modules import exceptions, models, rate_limit
from pyninja.monitor import get_all_monitor_routes

BASE_LOGGER = logging.getLogger("BASE_LOGGER")
BASE_LOGGER.setLevel(logging.INFO)
LOGGER = logging.getLogger("uvicorn.default")

PyNinjaAPI = FastAPI(
title="PyNinja",
version=version.__version__,
Expand Down Expand Up @@ -93,8 +89,8 @@ async def redirect_exception_handler(
JSONResponse:
Returns the JSONResponse with content, status code and cookie.
"""
LOGGER.debug("Exception headers: %s", request.headers)
LOGGER.debug("Exception cookies: %s", request.cookies)
logger.LOGGER.debug("Exception headers: %s", request.headers)
logger.LOGGER.debug("Exception cookies: %s", request.cookies)
if request.url.path == "/login":
response = JSONResponse(
content={"redirect_url": exception.location}, status_code=200
Expand Down Expand Up @@ -127,6 +123,10 @@ def start(**kwargs) -> None:
log_config: Logging configuration as a dict or a FilePath. Supports .yaml/.yml, .json or .ini formats.
"""
models.env = squire.load_env(**kwargs)
if models.env.log:
logger.LOGGER = logger.default_logger(models.env.log == models.LogOptions.file)
else:
logger.LOGGER = logging.getLogger("uvicorn.default")
dependencies = [
Depends(dependency=rate_limit.RateLimiter(each_rate_limit).init)
for each_rate_limit in models.env.rate_limit
Expand All @@ -135,7 +135,8 @@ def start(**kwargs) -> None:
arg1, arg2 = False, False
# Conditional endpoint based on remote_execution and api_secret
if all((models.env.remote_execution, models.env.api_secret)):
BASE_LOGGER.info(
logger.LOGGER.info("Remove execution enabled")
logger.LOGGER.info(
"Creating '%s' to handle authentication errors", models.env.database
)
models.database = models.Database(models.env.database)
Expand All @@ -150,17 +151,18 @@ def start(**kwargs) -> None:
)
arg1 = True
else:
BASE_LOGGER.warning("Remote execution disabled")
logger.LOGGER.warning("Remote execution disabled")
# Conditional endpoint based on monitor_username and monitor_password
if all((models.env.monitor_username, models.env.monitor_password)):
logger.LOGGER.info("Monitoring feature enabled")
PyNinjaAPI.routes.extend(get_all_monitor_routes(dependencies))
PyNinjaAPI.add_exception_handler(
exc_class_or_status_code=exceptions.RedirectException,
handler=redirect_exception_handler, # noqa: PyTypeChecker
)
arg2 = True
else:
BASE_LOGGER.warning("Monitoring feature disabled")
logger.LOGGER.warning("Monitoring feature disabled")
PyNinjaAPI.description = get_desc(arg1, arg2)
module_name = pathlib.Path(__file__)
kwargs = dict(
Expand All @@ -170,4 +172,5 @@ def start(**kwargs) -> None:
)
if models.env.log_config:
kwargs["log_config"] = models.env.log_config
logger.LOGGER.info("Starting uvicorn server")
uvicorn.run(**kwargs)
Loading

0 comments on commit 26305b1

Please sign in to comment.