Production ready.
Some checks failed
Build / Build (push) Has been cancelled

This commit is contained in:
retoor 2024-12-05 08:18:01 +01:00
parent d3b97c8e83
commit c8d17169a4
14 changed files with 155 additions and 60 deletions

View File

@ -0,0 +1,26 @@
name: Build
run-name: Build and test
on: [push]
jobs:
Build:
runs-on: ubuntu-latest
steps:
- name: Check out repository code
uses: actions/checkout@v4
- name: Update repo
run: git pull
- name: List files in the repository
run: |
ls ${{ gitea.workspace }}
- name: Update apt
run: apt update
- name: Installing system dependencies
run: apt install python3 python3-pip python3-venv make -y
- name: Run Make
run: make
- run: git add .
- run: git config --global user.email "bot@molodetz.com"
- run: git config --global user.name "bot"
- run: git commit -a -m "Automated update of package."
- run: git push

View File

@ -28,7 +28,7 @@ serve: ensure_env
$(BIN)mololog.serve --host=0.0.0.0 --port=3016 --db=mololog.db $(BIN)mololog.serve --host=0.0.0.0 --port=3016 --db=mololog.db
test: ensure_env test: ensure_env
$(BIN)mololog.test --url=http://localhost:3016 $(PYTHON) test.py
bench: ensure_env bench: ensure_env
$(BIN)mololog.bench --url=http://localhost:3016 $(BIN)mololog.bench --url=http://localhost:3016

View File

@ -1,5 +1,5 @@
[metadata] [metadata]
name = Mololog name = mololog
version = 1.3.37 version = 1.3.37
description = HTTP Logging service description = HTTP Logging service
author = Retoor author = Retoor
@ -16,7 +16,8 @@ python_requires = >=3.7
install_requires = install_requires =
requests==2.32.3 requests==2.32.3
aiohttp aiohttp
app @ git+https://retoor.molodetz.nl/retoor/app@main app @ git+https://retoor.molodetz.nl/retoor/app.git
# zhurnal @ git+https://retoor.molodetz.nl/retoor/zhurnal.git
[options.packages.find] [options.packages.find]
where = src where = src

View File

@ -10,3 +10,4 @@ Description-Content-Type: text/markdown
Requires-Dist: requests==2.32.3 Requires-Dist: requests==2.32.3
Requires-Dist: aiohttp Requires-Dist: aiohttp
Requires-Dist: app@ git+https://retoor.molodetz.nl/retoor/app@main Requires-Dist: app@ git+https://retoor.molodetz.nl/retoor/app@main
Requires-Dist: zhurnal@ git+https://retoor.molodetz.nl/retoor/zhurnal@main

View File

@ -1,3 +1,4 @@
requests==2.32.3 requests==2.32.3
aiohttp aiohttp
app@ git+https://retoor.molodetz.nl/retoor/app@main app@ git+https://retoor.molodetz.nl/retoor/app@main
zhurnal@ git+https://retoor.molodetz.nl/retoor/zhurnal@main

View File

@ -0,0 +1,12 @@
Metadata-Version: 2.1
Name: mololog
Version: 1.3.37
Summary: HTTP Logging service
Author: Retoor
Author-email: retoor@molodetz.nl
License: MIT
Requires-Python: >=3.7
Description-Content-Type: text/markdown
Requires-Dist: requests==2.32.3
Requires-Dist: aiohttp
Requires-Dist: app@ git+https://retoor.molodetz.nl/retoor/app.git

View File

@ -0,0 +1,12 @@
pyproject.toml
setup.cfg
src/mololog/__init__.py
src/mololog/__main__.py
src/mololog/client.py
src/mololog/server.py
src/mololog.egg-info/PKG-INFO
src/mololog.egg-info/SOURCES.txt
src/mololog.egg-info/dependency_links.txt
src/mololog.egg-info/entry_points.txt
src/mololog.egg-info/requires.txt
src/mololog.egg-info/top_level.txt

View File

@ -0,0 +1 @@

View File

@ -0,0 +1,4 @@
[console_scripts]
mololog.bench = mololog.client:bench
mololog.serve = mololog.server:serve
mololog.test = mololog.client:test

View File

@ -0,0 +1,3 @@
requests==2.32.3
aiohttp
app@ git+https://retoor.molodetz.nl/retoor/app.git

View File

@ -0,0 +1 @@
mololog

View File

@ -1,36 +1,32 @@
import logging
import json
import code
import requests
import argparse import argparse
import json
import logging
import time import time
from concurrent.futures import ThreadPoolExecutor as Executor from concurrent.futures import ThreadPoolExecutor as Executor
import requests
def parse_args(): def parse_args():
parser = argparse.ArgumentParser(description="Mololog client.") parser = argparse.ArgumentParser(description="Mololog client.")
parser.add_argument( parser.add_argument("--url", type=str, required=True)
"--url",
type=str,
required=True
)
return parser.parse_args() return parser.parse_args()
from requests.adapters import HTTPAdapter from requests.adapters import HTTPAdapter
log = logging.getLogger("mololog") log = logging.getLogger("mololog")
class HTTPLogger(logging.Handler): class HTTPLogger(logging.Handler):
def __init__(self, url): def __init__(self, url):
self.url = url.rstrip("/") + "/emit" self.url = url.rstrip("/") + "/emit"
self.session = requests.Session() self.session = requests.Session()
self.session.max_redirects =100 self.session.max_redirects = 100
self.adapter = HTTPAdapter(max_retries=10) self.adapter = HTTPAdapter(max_retries=10)
self.session.mount(self.url[:self.url.find("://")+2], self.adapter) self.session.mount(self.url[: self.url.find("://") + 2], self.adapter)
self.total_sent = 0 self.total_sent = 0
self.total_send = 0 self.total_send = 0
self.total_queued = 0 self.total_queued = 0
@ -43,13 +39,14 @@ class HTTPLogger(logging.Handler):
return False return False
self.total_send += 1 self.total_send += 1
self.total_queued += 1 self.total_queued += 1
def send(me, record): def send(me, record):
me.session.post(me.url,data=record) me.session.post(me.url, data=record)
me.total_sent += 1 me.total_sent += 1
me.total_queued -= 1 me.total_queued -= 1
print("DONE",me.total_queued,flush=True)
try: try:
self.executor.submit(send,self,json.dumps(record.__dict__,default=str)) self.executor.submit(send, self, json.dumps(record.__dict__, default=str))
except Exception as ex: except Exception as ex:
print(ex) print(ex)
@ -63,14 +60,17 @@ class HTTPLogger(logging.Handler):
def __del__(self): def __del__(self):
self.shutdown() self.shutdown()
def get_logger_names(): def get_logger_names():
root_logger = logging.getLogger() root_logger = logging.getLogger()
for child in root_logger.getChildren(): for child in root_logger.getChildren():
yield child.name yield child.name
http_logger = None http_logger = None
def patch(url,level=logging.INFO):
def patch(url, level=logging.INFO):
global http_logger global http_logger
http_logger = HTTPLogger(url) http_logger = HTTPLogger(url)
for name in get_logger_names(): for name in get_logger_names():
@ -80,6 +80,7 @@ def patch(url,level=logging.INFO):
logger.setLevel(level) logger.setLevel(level)
logger.addHandler(http_logger) logger.addHandler(http_logger)
def test(): def test():
args = parse_args() args = parse_args()
test_logger = logging.getLogger("mololog.test") test_logger = logging.getLogger("mololog.test")
@ -89,6 +90,7 @@ def test():
test_logger.warn("Test 2") test_logger.warn("Test 2")
test_logger.warn("Test 3") test_logger.warn("Test 3")
def bench(): def bench():
args = parse_args() args = parse_args()
bench_logger = logging.getLogger("mololog.bench") bench_logger = logging.getLogger("mololog.bench")
@ -97,8 +99,8 @@ def bench():
time_start = time.time() time_start = time.time()
count = 0 count = 0
while time.time() - time_start <= 10: while time.time() - time_start <= 10:
bench_logger.info("New line on {}".format(time.time())) bench_logger.info(f"New line on {time.time()}")
count += 1 count += 1
print(http_logger.total_queued) print(http_logger.total_queued)
print("Requests per second: {}".format(count / 10)) print(f"Requests per second: {count / 10}")
http_logger.shutdown() http_logger.shutdown()

View File

@ -1,54 +1,64 @@
from app.app import Application as BaseApplication
import asyncio
from aiohttp import web
import json import json
import uuid import uuid
import asyncio
from aiohttp import web
from app.app import Application as BaseApplication
class Application(BaseApplication): class Application(BaseApplication):
def __init__(self, test=0, *args, **kwargs):
self.test = test
self.total_received = 0
def __init__(self,*args,**kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.router.add_post("/emit",self.handle_emit) self.middlewares.append(self.test_middleware)
self.router.add_post("/emit", self.handle_emit)
async def exit_app(self):
await asyncio.sleep(1)
exit(0)
@web.middleware
async def test_middleware(self,request,handler):
result = await handler(request)
if self.total_received == self.test:
await asyncio.create_task(self.exit_app())
return result
async def handle_emit(self, request): async def handle_emit(self, request):
data = await request.json() data = await request.json()
for key,value in data.items(): for key, value in data.items():
if type(value) == list or type(value) == dict or type(value) == tuple: if type(value) == list or type(value) == dict or type(value) == tuple:
data[key] = json.dumps(value,default=str) data[key] = json.dumps(value, default=str)
data['uid'] = str(uuid.uuid4()) data["uid"] = str(uuid.uuid4())
result = await self.insert("log", data) await self.insert("log", data)
return web.json_response(data['uid'],content_type="application/json") self.total_received += 1
return web.json_response(data["uid"], content_type="application/json")
import argparse import argparse
def parse_args(): def parse_args():
parser = argparse.ArgumentParser(description="Mololog server.") parser = argparse.ArgumentParser(description="Mololog server.")
parser.add_argument( parser.add_argument("--host", type=str, required=True)
"--host", parser.add_argument("--port", type=int, required=True)
type=str, parser.add_argument("--db", type=str, required=True)
required=True parser.add_argument("--test", type=int, required=False,default=0)
)
parser.add_argument(
"--port",
type=int,
required=True
)
parser.add_argument(
"--db",
type=str,
required=True
)
return parser.parse_args() return parser.parse_args()
def serve(): def serve():
args = parse_args() args = parse_args()
app = Application(db_path="sqlite:///{}".format(args.db)) app = Application(db_path=f"sqlite:///{args.db}",test=args.test)
app.run(host=args.host, port=args.port) app.run(host=args.host, port=args.port)

21
test.py Normal file
View File

@ -0,0 +1,21 @@
import subprocess
import shlex
import time
processes = [
subprocess.Popen(shlex.split("./.venv/bin/mololog.serve --host=127.0.0.1 --port=3999 --db=':memory:' --test=3")),
subprocess.Popen(shlex.split("./.venv/bin/mololog.test --url=http://localhost:3999"))
]
for process in processes:
while True:
process.poll()
if not process.returncode is None:
if process.returncode != 0:
exit(process.returncode)
break
time.sleep(1)
print("Test sucess!")