From 186cc76ce18f343cfcb4078ddcf2b9ec3c3871db Mon Sep 17 00:00:00 2001 From: Miguel BarĂ£o Date: Mon, 6 May 2019 23:50:10 +0100 Subject: [PATCH] adds config/logger.yaml files as a base for customization. --- BUGS.md | 1 + README.md | 15 +++++++++------ aprendizations/knowledge.py | 24 +++++++++--------------- aprendizations/learnapp.py | 2 ++ aprendizations/questions.py | 8 ++++---- aprendizations/serve.py | 25 ++++++++++++++----------- config/logger-debug.yaml | 46 ++++++++++++++++++++++++++++++++++++++++++++++ config/logger.yaml | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 131 insertions(+), 36 deletions(-) create mode 100644 config/logger-debug.yaml create mode 100644 config/logger.yaml diff --git a/BUGS.md b/BUGS.md index 0ad4c29..bf2d5fd 100644 --- a/BUGS.md +++ b/BUGS.md @@ -1,6 +1,7 @@ # BUGS +- permitir configuracao para escolher entre static files locais ou remotos - sqlalchemy.pool.impl.NullPool: Exception during reset or similar sqlite3.ProgrammingError: SQLite objects created in a thread can only be used in that same thread. diff --git a/README.md b/README.md index 6bd2643..358c9d1 100644 --- a/README.md +++ b/README.md @@ -85,8 +85,9 @@ At this point aprendizations is installed in ~/.local/bin # FreeBSD/Linux ``` -and can be run with the command `aprendizations` (make sure this directory is -in your `$PATH`). +Make sure this directory is in your `$PATH`. + +The server can be run with the command `aprendizations` from the terminal. ## Configuration @@ -121,7 +122,7 @@ have a registered publicly accessible domain name. #### Selfsigned -Generate a selfsigned certificate and place it in `aprendizations/certs`. +Generate a selfsigned certificate and place it in `~/.local/share/certs`. ```sh openssl req -x509 -newkey rsa:4096 -keyout privkey.pem -out cert.pem -days 365 -nodes @@ -141,7 +142,7 @@ sudo certbot certonly --standalone -d www.example.com sudo service pf start # enable pf firewall ``` -Certificates are saved under `/usr/local/etc/letsencrypt/live/www.example.com/`. Copy them to `aprendizations/certs` and change permissions to be readable: +Certificates are saved under `/usr/local/etc/letsencrypt/live/www.example.com/`. Copy them to `~/.local/share/certs` and change permissions to be readable: ```sh sudo cp /usr/local/etc/letsencrypt/live/www.example.com/cert.pem . @@ -157,7 +158,7 @@ sudo certbot renew sudo service pf start # start firewall ``` -and then copy the `cert.pem` and `privkey.pem` files to `aprendizations/certs` directory. Change permissions and ownership as appropriate. +and then copy the `cert.pem` and `privkey.pem` files to `~/.local/share/certs` directory. Change permissions and ownership as appropriate. ### Testing @@ -169,7 +170,8 @@ cd demo aprendizations demo.yaml ``` -and open a browser at [https://127.0.0.1:8443](). If it everything looks good, +and open a browser at [https://127.0.0.1:8443](https://127.0.0.1:8443). +If it everything looks good, check at the correct address `https://www.example.com` (requires port forward in the firewall). The option `--debug` provides more verbose logging and might be useful during testing. The option `--check` generates all the questions once @@ -220,6 +222,7 @@ errors in the browser. Logging levels can be adjusted in `~/.config/aprendizations/logger.yaml` and `~/.config/aprendizations/logger-debug.yaml`. +If these files do not yet exist, there are examples in `aprendizations/config` that can be copied to `~/.config/aprendizations`. #### UnicodeEncodeError diff --git a/aprendizations/knowledge.py b/aprendizations/knowledge.py index ec7c73f..cb774c6 100644 --- a/aprendizations/knowledge.py +++ b/aprendizations/knowledge.py @@ -69,13 +69,14 @@ class StudentKnowledge(object): # ------------------------------------------------------------------------ async def start_topic(self, topic): logger.debug('StudentKnowledge.start_topic()') + if self.current_topic == topic: - logger.info(' Restarting current topic is not allowed.') + logger.info('Restarting current topic is not allowed.') return False # do not allow locked topics if self.is_locked(topic): - logger.debug(f' Topic {topic} is locked') + logger.debug(f'Topic {topic} is locked') return False # starting new topic @@ -96,23 +97,16 @@ class StudentKnowledge(object): # synchronous: # self.questions = [self.factory[ref].generate() for ref in questions] - loop = asyncio.get_running_loop() - # async: - # generators = [loop.run_in_executor(None, self.factory[qref].generate) - # for qref in questions] - # self.questions = await asyncio.gather(*generators) - - # another async: - self.questions = [] - for qref in questions: - q = await loop.run_in_executor(None, self.factory[qref].generate) - self.questions.append(q) - - logger.debug(f'Generated {len(self.questions)} questions') + loop = asyncio.get_running_loop() + generators = [loop.run_in_executor(None, self.factory[qref].generate) + for qref in questions] + self.questions = await asyncio.gather(*generators) # get first question self.next_question() + + logger.debug(f'Generated {len(self.questions)} questions') return True # ------------------------------------------------------------------------ diff --git a/aprendizations/learnapp.py b/aprendizations/learnapp.py index 1d3fb98..02df6d5 100644 --- a/aprendizations/learnapp.py +++ b/aprendizations/learnapp.py @@ -459,3 +459,5 @@ class LearnApp(object): for uid, name in students if uid != '0'] return sorted(rankings, key=lambda x: x[2], reverse=True) + + # ------------------------------------------------------------------------ diff --git a/aprendizations/questions.py b/aprendizations/questions.py index fc83b70..3bbc7df 100644 --- a/aprendizations/questions.py +++ b/aprendizations/questions.py @@ -28,9 +28,9 @@ class QuestionException(Exception): # =========================================================================== class Question(dict): ''' - Classes derived from this base class are meant to instantiate a question - to a student. - Instances can shuffle options, or automatically generate questions. + Classes derived from this base class are meant to instantiate questions + for each student. + Instances can shuffle options or automatically generate questions. ''' def __init__(self, q: QDict) -> None: super().__init__(q) @@ -125,7 +125,7 @@ class QuestionRadio(Question): self['correct'] = [float(correct[i]) for i in perm] # ------------------------------------------------------------------------ - # can return negative values for wrong answers + # can assign negative grades for wrong answers def correct(self) -> None: super().correct() diff --git a/aprendizations/serve.py b/aprendizations/serve.py index fb45113..d0ebd6c 100644 --- a/aprendizations/serve.py +++ b/aprendizations/serve.py @@ -1,8 +1,6 @@ #!/usr/bin/env python3 # python standard library -from os import path -import os import sys import base64 import uuid @@ -13,12 +11,12 @@ import signal import functools import ssl import asyncio -# from typing import NoReturn +from os import path, environ # third party libraries import tornado.ioloop -import tornado.web import tornado.httpserver +import tornado.web from tornado.escape import to_unicode # this project @@ -294,7 +292,7 @@ class QuestionHandler(BaseHandler): answer_qid = self.get_body_arguments('qid')[0] current_qid = self.learn.get_current_question_id(user) if answer_qid != current_qid: - logging.debug(f'User {user} desynchronized questions') + logging.info(f'User {user} desynchronized questions') self.write({ 'method': 'invalid', 'params': { @@ -428,16 +426,16 @@ def get_logger_config(debug=False): filename = 'logger.yaml' level = 'INFO' - config_dir = os.environ.get('XDG_CONFIG_HOME', '~/.config/') + config_dir = environ.get('XDG_CONFIG_HOME', '~/.config/') config_file = path.join(path.expanduser(config_dir), APP_NAME, filename) default_config = { 'version': 1, 'formatters': { 'standard': { - 'format': '%(asctime)s %(name)-24s %(levelname)-8s ' + 'format': '%(asctime)s %(name)-24s %(levelname)-10s - ' '%(message)s', - 'datefmt': '%H:%M:%S', + 'datefmt': '%Y-%m-%d %H:%M:%S', }, }, 'handlers': { @@ -503,8 +501,8 @@ def main(): sys.exit(1) # --- get SSL certificates - if 'XDG_DATA_HOME' in os.environ: - certs_dir = path.join(os.environ['XDG_DATA_HOME'], 'certs') + if 'XDG_DATA_HOME' in environ: + certs_dir = path.join(environ['XDG_DATA_HOME'], 'certs') else: certs_dir = path.expanduser('~/.local/share/certs') @@ -523,7 +521,12 @@ def main(): logging.critical('Certificates cert.pem and privkey.pem not found') sys.exit(1) - httpserver.listen(arg.port) + try: + httpserver.listen(arg.port) + except OSError: + logging.critical(f'Cannot bind port {arg.port}. Already in use?') + sys.exit(1) + logging.info(f'Listening on port {arg.port}.') # --- run webserver diff --git a/config/logger-debug.yaml b/config/logger-debug.yaml new file mode 100644 index 0000000..8642783 --- /dev/null +++ b/config/logger-debug.yaml @@ -0,0 +1,46 @@ +--- +version: 1 + +formatters: + void: + format: '' + standard: + format: '%(asctime)s | %(levelname)-9s | %(name)-24s | %(thread)-15d | %(message)s' + datefmt: '%H:%M:%S' + +handlers: + default: + level: 'DEBUG' + class: 'logging.StreamHandler' + formatter: 'standard' + stream: 'ext://sys.stdout' + +loggers: + '': + handlers: ['default'] + level: 'DEBUG' + + 'aprendizations.factory': + handlers: ['default'] + level: 'DEBUG' + propagate: false + + 'aprendizations.knowledge': + handlers: ['default'] + level: 'DEBUG' + propagate: false + + 'aprendizations.learnapp': + handlers: ['default'] + level: 'DEBUG' + propagate: false + + 'aprendizations.questions': + handlers: ['default'] + level: 'DEBUG' + propagate: false + + 'aprendizations.tools': + handlers: ['default'] + level: 'DEBUG' + propagate: false diff --git a/config/logger.yaml b/config/logger.yaml new file mode 100644 index 0000000..bf54e54 --- /dev/null +++ b/config/logger.yaml @@ -0,0 +1,46 @@ +--- +version: 1 + +formatters: + void: + format: '' + standard: + format: '%(asctime)s | %(thread)-15d | %(levelname)-9s | %(message)s' + datefmt: '%Y-%m-%d %H:%M:%S' + +handlers: + default: + level: 'INFO' + class: 'logging.StreamHandler' + formatter: 'standard' + stream: 'ext://sys.stdout' + +loggers: + '': + handlers: ['default'] + level: 'INFO' + + 'aprendizations.factory': + handlers: ['default'] + level: 'INFO' + propagate: false + + 'aprendizations.knowledge': + handlers: ['default'] + level: 'INFO' + propagate: false + + 'aprendizations.learnapp': + handlers: ['default'] + level: 'INFO' + propagate: false + + 'aprendizations.questions': + handlers: ['default'] + level: 'INFO' + propagate: false + + 'aprendizations.tools': + handlers: ['default'] + level: 'INFO' + propagate: false -- libgit2 0.21.2