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

Add bridged logger. Improves performance substantially. #201

Merged
merged 1 commit into from
May 28, 2022
Merged
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
19 changes: 19 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -34,6 +34,8 @@ uuid = { version = "0.8", features = ["serde", "v4"] }
serde = "1.0.136"
serde_json = "1.0.79"
futures = "0.3.21"
pyo3-log = "0.4.1"
log = "0.4.17"

[features]
# Defines a feature named `webp` that does not enable any other features.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -89,7 +89,8 @@ optional arguments:
-h, --help show this help message and exit
--processes PROCESSES : allows you to choose the number of parallel processes
--workers WORKERS : allows you to choose the number of workers
--dev DEV : this flag gives the option to enable hot reloading or not
--dev DEV : this flag gives the option to enable hot reloading or not and also sets the default log level to debug
--log-level LEVEL : this flag allows you to set the log level
```


4 changes: 2 additions & 2 deletions docs/api.md
Original file line number Diff line number Diff line change
@@ -183,13 +183,13 @@ You can add startup and shutdown events in robyn. These events will execute befo
```python3

async def startup_handler():
logger.log(logging.INFO, "Starting up")
print("Starting up")

app.startup_handler(startup_handler)

@app.shutdown_handler
def shutdown_handler():
logger.log(logging.INFO, "Shutting down")
print("Shutting down")
```

## WebSockets
11 changes: 3 additions & 8 deletions integration_tests/base_routes.py
Original file line number Diff line number Diff line change
@@ -2,10 +2,6 @@
import asyncio
import os
import pathlib
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

app = Robyn(__file__)
websocket = WS(app, "/web_socket")
@@ -156,12 +152,12 @@ def blocker():


async def startup_handler():
logger.log(logging.INFO, "Starting up")
print("Starting up")


@app.shutdown_handler
def shutdown_handler():
logger.log(logging.INFO, "Shutting down")
print("Shutting down")


@app.get("/redirect")
@@ -178,10 +174,9 @@ async def redirect_route(request):
ROBYN_URL = os.getenv("ROBYN_URL", "0.0.0.0")
app.add_header("server", "robyn")
current_file_path = pathlib.Path(__file__).parent.resolve()
os.path.join(current_file_path, "build")
app.add_directory(
route="/test_dir",
directory_path=os.path.join(current_file_path, "build/"),
directory_path=os.path.join(current_file_path, "build"),
index_file="index.html",
)
app.startup_handler(startup_handler)
11 changes: 11 additions & 0 deletions integration_tests/build/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<p>Hello world</p>
</body>
</html>
36 changes: 29 additions & 7 deletions robyn/__init__.py
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@
from inspect import signature
import multiprocessing as mp
from robyn.events import Events
import logging

# custom imports and exports
from .robyn import SocketHeld
@@ -19,8 +20,11 @@
from multiprocess import Process
from watchdog.observers import Observer


mp.allow_connection_pickling()

logger = logging.getLogger(__name__)


class Robyn:
"""This is the python wrapper for the Robyn binaries."""
@@ -30,16 +34,19 @@ def __init__(self, file_object):
self.file_path = file_object
self.directory_path = directory_path
self.parser = ArgumentParser()
self.dev = self.parser.is_dev()
self.processes = self.parser.num_processes()
self.workers = self.parser.workers()
self.dev = self.parser.is_dev
self.processes = self.parser.num_processes
self.workers = self.parser.workers
self.log_level = self.parser.log_level
self.router = Router()
self.middleware_router = MiddlewareRouter()
self.web_socket_router = WebSocketRouter()
self.headers = []
self.directories = []
self.event_handlers = {}

self._config_logger()

def _add_route(self, route_type, endpoint, handler):
"""
[This is base handler for all the decorators]
@@ -83,7 +90,7 @@ def add_web_socket(self, endpoint, ws):
self.web_socket_router.add_route(endpoint, ws)

def _add_event_handler(self, event_type: str, handler):
print(f"Add event {event_type} handler")
logger.debug(f"Add event {event_type} handler")
if event_type not in {Events.STARTUP, Events.SHUTDOWN}:
return

@@ -125,18 +132,19 @@ def start(self, url="127.0.0.1", port=5000):
p.start()
processes.append(p)

print("Press Ctrl + C to stop \n")
logger.info(f"{Colors.HEADER}Starting up \n{Colors.ENDC}")
logger.info(f"{Colors.OKGREEN}Press Ctrl + C to stop \n{Colors.ENDC}")
try:
for process in processes:
process.join()
except KeyboardInterrupt:
print(f"\n{Colors.BOLD}{Colors.OKGREEN} Terminating server!! {Colors.ENDC}")
logger.info(f"{Colors.BOLD}{Colors.OKGREEN} Terminating server!! {Colors.ENDC}")
for process in processes:
process.kill()
else:
event_handler = EventHandler(self.file_path)
event_handler.start_server_first_time()
print(
logger.info(
f"{Colors.OKBLUE}Dev server initialised with the directory_path : {self.directory_path}{Colors.ENDC}"
)
observer = Observer()
@@ -255,3 +263,17 @@ def inner(handler):
self._add_route("TRACE", endpoint, handler)

return inner

def _config_logger(self):
"""
This is the method to configure the logger either on the dev mode or the env variable
"""

log_level = "WARN"

if self.dev:
log_level = "DEBUG"

log_level = self.log_level if self.log_level else log_level
logging.basicConfig(level=log_level)

14 changes: 14 additions & 0 deletions robyn/argument_parser.py
Original file line number Diff line number Diff line change
@@ -28,14 +28,28 @@ def __init__(self):
help="Development mode. It restarts the server based on file changes.",
)

self.parser.add_argument(
"--log-level",
dest="log_level",
default="INFO",
help="Set the log level name",
)

self.args = self.parser.parse_args()

@property
def num_processes(self):
return self.args.processes

@property
def workers(self):
return self.args.workers

@property
def log_level(self):
return self.args.log_level

@property
def is_dev(self):
_is_dev = self.args.dev
if _is_dev and (self.num_processes() != 1 or self.workers() != 1):
24 changes: 20 additions & 4 deletions robyn/argument_parser.pyi
Original file line number Diff line number Diff line change
@@ -1,7 +1,23 @@
import argparse


class ArgumentParser(argparse.ArgumentParser):
def __init__(self) -> None: ...
def num_processes(self): ...
def workers(self): ...
def is_dev(self): ...
def __init__(self) -> None:
...

@property
def num_processes(self) -> int:
...

@property
def workers(self) -> int:
...

@property
def is_dev(self) -> bool:
...

@property
def log_level(self) -> str:
...

9 changes: 3 additions & 6 deletions robyn/dev_event_handler.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# default imports
import subprocess

# custom imports
from .log_colors import Colors

# third party imports
from watchdog.events import FileSystemEventHandler
import logging

logger = logging.getLogger(__name__)


class EventHandler(FileSystemEventHandler):
@@ -16,8 +16,6 @@ def __init__(self, file_name):
def start_server_first_time(self):
if self.processes:
raise Exception("Something wrong with the server")

print(f"{Colors.OKGREEN}Starting the server in dev mode{Colors.ENDC}")
self.processes.append(subprocess.Popen(["python3", self.file_name], start_new_session=False))

def on_any_event(self, event):
@@ -30,5 +28,4 @@ def on_any_event(self, event):
if len(self.processes) > 0:
for process in self.processes:
process.terminate()
print(f"{Colors.OKGREEN}Starting the server in dev mode{Colors.ENDC}")
self.processes.append(subprocess.Popen(["python3", self.file_name], start_new_session=False))
4 changes: 2 additions & 2 deletions robyn/processpool.py
Original file line number Diff line number Diff line change
@@ -4,8 +4,9 @@
import sys
import multiprocessing as mp
import asyncio
import logging

# import platform
logger = logging.getLogger(__name__)


mp.allow_connection_pickling()
@@ -67,7 +68,6 @@ def spawn_process(

for endpoint in web_sockets:
web_socket = web_sockets[endpoint]
print(web_socket.methods)
server.add_web_socket_route(
endpoint,
web_socket.methods["connect"],
1 change: 0 additions & 1 deletion robyn/router.py
Original file line number Diff line number Diff line change
@@ -19,7 +19,6 @@ def _format_response(self, res):
response = {}
if type(res) == dict:
if "status_code" not in res:
print("Getting here")
res["status_code"] = "200"
response = res
else:
7 changes: 4 additions & 3 deletions src/executors/mod.rs
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@ use std::sync::Arc;

use actix_web::{http::Method, web, HttpRequest};
use anyhow::{bail, Result};
use log::debug;
// pyO3 module
use crate::types::{Headers, PyFunction};
use futures_util::stream::StreamExt;
@@ -187,7 +188,7 @@ pub async fn execute_http_function(

let output = output.await?;
let res = Python::with_gil(|py| -> PyResult<HashMap<String, String>> {
println!("This is the result of the code {:?}", output);
debug!("This is the result of the code {:?}", output);

let mut res: HashMap<String, String> =
output.into_ref(py).downcast::<PyDict>()?.extract()?;
@@ -238,15 +239,15 @@ pub async fn execute_event_handler(
if let Some(handler) = event_handler {
match &(*handler) {
PyFunction::SyncFunction(function) => {
println!("Startup event handler");
debug!("Startup event handler");
Python::with_gil(|py| -> Result<(), Box<dyn std::error::Error>> {
function.call0(py)?;
Ok(())
})?;
}
PyFunction::CoRoutine(function) => {
let future = Python::with_gil(|py| {
println!("Startup event handler async");
debug!("Startup event handler async");

let coroutine = function.as_ref(py).call0().unwrap();
pyo3_asyncio::into_future_with_loop((*event_loop).as_ref(py), coroutine)
Loading