I need to dynamically change log level without reloading any modules. For this, I am using a combination of asyncio and multiprocessing (both for the bigger program that I am writing).
log_config.py
def setupLogging(log_level=None): # load custom logger
with open(os.path.join(LOG_PATH,'log_config.yaml'), 'rt') as file_:
config = yaml.safe_load(file_.read())
logging.config.dictConfig(config)
logging.Formatter.converter = time.gmtime
if not log_level:
log_level = 'preview'
return logging.getLogger(log_level)
logger=setupLogging() # global var that needs dynamic updation
async def logger_changes(): # socket listener that changes the logger object
global logger
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('localhost', 9999))
sock.listen()
sock.setblocking(0)
while True:
try:
conn, addr = sock.accept()
data = conn.recv(1024)
conn.send(data)
logger = setupLogging(data.decode('utf8'))
except Exception as e:
pass
await asyncio.sleep(5)
async def logger_handler():
t1 = asyncio.create_task(logger_changes())
await t1
def start_logger():
start_func = asyncio.run(logger_handler())
pLOGGER = Process(name="__startLOGGER__", target=start_logger, daemon=False)
pLOGGER.start()
Main Functionality
import log_config
logger=log_config.logger
async def core_func():
for i in range(10):
logger.debug("sample debug log")
logger.info("sample info log")
logger.warning("Watch out!")
logger.error("Heading for trouble!")
logger.critical("Seriously, do something!")
print("#"*80)
await asyncio.sleep(5)
async def core_func_parent():
t1 = asyncio.create_task(core_func())
await t1
def core_func_handler():
start_func = asyncio.run(core_func_parent())
if __name__=='__main__':
pMODULE = Process(name="__startMODULE__", target=core_func_handler, daemon=False)
pMODULE.start()
Trigger Log Level Change
import socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.connect(('localhost', 9999))
request = "test"
try:
server.send(request.encode('utf8'))
response = server.recv(255).decode('utf8')
print(response)
except Exception as e:
print(e)
server.close()
Steps
Run main functionality python script. Automatically invoked log_config from inside, starts the socket listener and instantiates the logger object
Run trigger log level change that sends a message to the web socket with the updated logger setting
Challenge
Once I run step 1, the logging level is INFO (which is exactly what I want)
But once I run step 2, I am expecting the logging level to change to DEBUG which is not happening.
Any help is appreciated.
Related
import asyncio
import websockets
import threading
async def server_handle(websocket,path):
print("Server is waiting!!!!")
while True:
msg = await websocket.recv()
print(f"Client : {msg}")
await websocket.send(input("Server : "))
def add_new_clients():
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
start_server = websockets.serve(server_handle, "localhost", 1234)
loop.run_until_complete(start_server)
loop.run_forever()
loop.close()
total_clients = 0
if __name__ == "__main__":
# daemon server thread:
server = threading.Thread(target=add_new_clients, daemon=True)
server.start()
total_clients+=1
print(f"total clients : {total_clients}")
Here i am trying to add new thread to handle each clients request seperately using python websockets . for example if client1 connects to the server one thread should be created and sholud take care of the request and responce of that particular client. is there any way?.
Although the question might seem simple I can't see to find a viable way or anyway of printing the incoming messages from a threaded websocket.
Basically, I've created a jupyterlab notebook that lets me connect to a local websocket server and echo messages sent from a firecamp websocket connection. When running it on a cell (without the run button and run A.start()) I can see the prints but as soon as I hit the run button after restarting the kernal I can't see incoming messages.
Normally I would expect something like:
Function started
Someone said: test 1
Someone said: test 2
In the prints but nothing seems to apperas when hitting the run button.
The main objective is to be able to run the notebook with voila to upload to heroku but I canĀ“t seem to make the prints work. If anybody has a clue or a better idea, I'm all ears.
Thanks in advance.
PD: Code
import ipywidgets as widgets
from IPython.display import Javascript, display
import websocket
import asyncio
import nest_asyncio
import threading
import websocket
import time
import sys
import trace
import logging
from time import sleep
output_box = widgets.Output()
class KThread(threading.Thread):
"""A subclass of threading.Thread, with a kill() method."""
def __init__(self, *args, **keywords):
threading.Thread.__init__(self, *args, **keywords)
self.killed = False
def start(self):
"""Start the thread."""
self.__run_backup = self.run
self.run = self.__run
threading.Thread.start(self)
def __run(self):
"""Hacked run function, which installs the trace."""
sys.settrace(self.globaltrace)
self.__run_backup()
self.run = self.__run_backup
def globaltrace(self, frame, why, arg):
if why == 'call':
return self.localtrace
else:
return None
def localtrace(self, frame, why, arg):
if self.killed:
if why == 'line':
raise SystemExit()
return self.localtrace
def kill(self):
ws.close()
self.killed = True
def on_message(ws, message):
print(message)
def on_open(ws):
ws.send("Connected Test")
def on_close(ws, close_status_code, close_msg):
print("### closed ###")
def on_error(ws, error):
print(error)
#This illustrates running a function in a separate thread. The thread is killed before the function finishes.
def func():
print('Function started')
ws.run_forever()
ws = websocket.WebSocketApp("ws://localhost:7890", on_open=on_open,on_message = on_message, on_close = on_close,on_error = on_error)
A = KThread(target=func)
websocket.enableTrace(True)
run_button = widgets.Button(
description='Run Button',
disabled=False,
button_style='info', # 'success', 'info', 'warning', 'danger' or ''
tooltip='Run button function',
icon='play'
)
def on_run_button_clicked(b):
with output_box:
A.start()
run_button.on_click(on_run_button_clicked)
display(run_button,output_box)
This is the websocket server:
# Importing the relevant libraries
import websockets
import asyncio
# Server data
PORT = 7890
print("Server listening on Port " + str(PORT))
# A set of connected ws clients
connected = set()
# The main behavior function for this server
async def echo(websocket, path):
print("A client just connected")
# Store a copy of the connected client
print(websocket)
connected.add(websocket)
# Handle incoming messages
try:
async for message in websocket:
print("Received message from client: " + message)
# Send a response to all connected clients except sender
for conn in connected:
if conn != websocket:
await conn.send("Someone said: " + message)
# Handle disconnecting clients
except websockets.exceptions.ConnectionClosed as e:
print("A client just disconnected")
finally:
connected.remove(websocket)
# Start the server
start_server = websockets.serve(echo, "localhost", PORT)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
The fixed code (from https://medium.com/#rajatsaxena120/websockets-in-python-d91c7bc2fd22, https://stackoverflow.com/questions/ask?newreg=520c9b343e534667aa88f67ea3f79cb4) seems to work:
import time, websocket
from locust import HttpUser, task, between, events
from websocket import create_connection
import gevent
class QuickstartUser(HttpUser):
wait_time = between(1, 5)
#task
def on_start(self):
ws = create_connection('wss://REDACTED.com')
g = gevent.spawn(self.connect)
g.get(block=True, timeout=10)
g = gevent.spawn(self.subscribe)
g.get(block=True, timeout=10)
g = gevent.spawn(self.send)
g.get(block=True, timeout=10)
def _receive():
ws = create_connection('wss://REDACTED.com')
while True:
res = ws.recv()
events.request_success.fire(
request_type='Websocket Receive Message',
name='test websocket message receive',
response_time=0,
response_length=len(res)
)
gevent.spawn(_receive)
But when running tests, nothing happen, no connection to websocket, no load on the server.
What am I missing?
Am currently using python asynchronous server to server some clients , the server works well at first then eventually hangs without showing if it is receiving and requests from clients, when I press ctr-c it then shows that it receives the requests from the clients and it does not stop, it just continues to revieve requests .
I don't where this bug is emanating from.
Thank u in advance
import asyncio, json
from collections import Coroutine
from typing import Any
import Engine
import struct
header_struct = struct.Struct("!Q") # messages up to 2**64 - 1 in length
async def recvall(reader, length):
blocks = []
while length:
block = await reader.read(length)
if not block:
raise EOFError('socket closed with {} bytes left in this block'.format(length))
length -= len(block)
blocks.append(block)
return b''.join(blocks)
async def get_block(reader):
data = await recvall(reader, header_struct.size)
(block_length,) = header_struct.unpack(data)
return await recvall(reader, block_length)
async def put_block(writer, message):
block_length = len(message)
writer.write(header_struct.pack(block_length))
writer.write(message)
# await writer.drain()
async def handle_conversation(reader, writer):
address__ = writer.get_extra_info("peername")
print("Accepted connection from {}".format(address__))
while True:
# ************************try to check if there data to send*********************************
try:
block = await get_block(reader)
# decode the data
data = block.decode()
decoded_data = json.loads(data)
# dont forget to make this synchronous
answer = await Engine.get_answer(decoded_data["Task"], decoded_data["content"])
# don't forget to check in there is necessary data to push and making sure data is conveyed
await put_block(writer, answer)
print(answer)
except Exception as e:
raise
if __name__ == '__main__':
address = Engine.parse_command_line("asyncio server using coroutine")
# loop = asyncio.get_event_loop()
# coro = asyncio.start_server(handle_conversation, *address)
async def main():
server = await asyncio.start_server(
handle_conversation, *address)
addr = server.sockets[0].getsockname()
print(f'Serving on {addr}')
async with server:
await server.serve_forever()
asyncio.run(main(), debug=True)
Engine Code
import argparse
import json
import time
import upload_pic_and_search
import accept_connections
import connect
import opinion_poll
import share
import zmq
from jsonrpclib import Server
context = zmq.Context()
aphorisms = {"share": share.share_,
"poll": opinion_poll.add_poll,
"add_profile_pic": upload_pic_and_search.profile_pic,
"connect": connect.connect,
"accept_connection": accept_connections.accept_connection}
def sighn_up(doc):
"""this function will connect to sighn up """
proxy = Server('http://localhost:7002')
answer = proxy.sighn_up(doc)
return answer
def Verification(doc):
"""Code verification routine"""
proxy = Server('http://localhost:7002')
answer = proxy.verify(doc)
return answer
def login(doc):
"""This function handkes authetication"""
proxy = Server('http://localhost:7002')
answer = proxy.autheticate(doc)
return answer
def post(doc):
"""connect to server that handles posts"""
proxy = Server('http://localhost:6700')
answer = proxy.post(doc)
return answer
def comment(doc):
"""connect to the server that stores comments"""
proxy = Server('http://localhost:6701')
answer = proxy.comments_(doc)
return answer
def reply(doc):
"""store the reply"""
proxy = Server('http://localhost:6702')
answer = proxy.reply(doc)
return answer
def share(doc):
"""share the post"""
proxy = Server('http://localhost:6703')
answer = proxy.share(doc)
return answer
def likes(doc):
"""connect to the likes queue"""
zcontext = zmq.Context()
osock = zcontext.socket(zmq.PUSH)
osock.connect("tcp://127.0.0.1:6704")
osock.send_json(doc)
return {"Task": "like", "like": True}
def follow(doc):
"""handles the follow coroutine"""
zcontext = zmq.Context()
osock = zcontext.socket(zmq.PUSH)
osock.connect("tcp://127.0.0.1:6705")
osock.send_json(doc)
def connect(doc):
"""connect to routine for connection"""
zcontext = zmq.Context()
osock = zcontext.socket(zmq.PUSH)
osock.connect("tcp://127.0.0.1:6706")
osock.send_json(doc)
def accept_connection(doc):
"""the queue responsible accepting connections"""
zcontext = zmq.Context()
osock = zcontext.socket(zmq.PUSH)
osock.connect("tcp://127.0.0.1:6707")
osock.send_json(doc)
def add_profile_pic(doc):
"""Add the profile pic of the user"""
proxy = Server('http://localhost:7006')
answer = proxy.profile_pic(doc)
return answer
def search(doc):
"""search the user in the database"""
proxy = Server('http://localhost:7006')
answer = proxy.search(doc)
return answer
def profile(doc):
"""search the user in the database"""
proxy = Server('http://localhost:7006')
answer = proxy.profile(doc)
return answer
async def get_answer(aphorism, content):
"""Return the response to particular question"""
# time.sleep(0.0)
# fetch responsible function
# function = aphorisms.get(aphorism, "Error:Unknown aphorism.")
function = eval(aphorism)
answer = function(content)
return send(answer)
def send(data):
"""Prepare the data to be sent via socket"""
json_data = json.dumps(data)
data_bytes = json_data.encode()
return data_bytes
def parse_command_line(description):
"""arse command line and return a socket address."""
parser = argparse.ArgumentParser(description=description)
parser.add_argument('host', help="IP or hostname")
parser.add_argument("-p", metavar='port', type=int, default=1060, help="TCP port (default 1060)")
args = parser.parse_args()
address = (args.host, args.p)
return address
def recv_untill(sock, suffix):
"""Receive bytes over socket `sock` until we receive the `suffix`."""
message = sock.recv(4096)
if not message:
raise EOFError("Socket closed")
while not message.endswith(suffix):
data = sock.recv(4096)
if not data:
raise IOError('received {!r} then socket closed'.format(message))
message += data
return message
I have doubts about Python's await and hava an example,it tries to use await to fetch results from the future obj.
import time
import asyncio
import time
import random
import threading
db = {
"yzh": "pig",
"zhh": "big pig"
}
loop = asyncio.get_event_loop()
def _get_redis(username, clb):
def foo():
data = db[username]
time.sleep(0.1)
print("start clb")
clb(data)
t1 = threading.Thread(target=foo)
t1.start()
def get_redis(username):
print("start get redis")
myfuture = asyncio.Future()
def clb(result):
print("clb call")
myfuture.set_result(result)
_get_redis(username, clb)
return myfuture
async def main():
print("start main")
data = await get_redis("yzh")
print("data is {}".format(data))
loop.run_until_complete(asyncio.ensure_future(main()))
loop.close()
and i got output without future's result:
start main
start get redis
start clb
clb call
How should i use await to get the future's result?I tried many times. Thanks for your help.
As you said in your comment, you're supposed to use loop.call_soon_threadsafe when running an asyncio callback from a thread:
loop.call_soon_threadsafe(myfuture.set_result, result)
However, a better approach for calling a synchronous function from asyncio is to use loop.run_in_executor:
def _get_redis(username):
time.sleep(0.1)
return db[username]
async def get_redis(username):
return await loop.run_in_executor(None, _get_redis, username)
This way, you won't have to deal with futures and thread-safe callbacks.