Skip to content

Commit f8034f2

Browse files
authored
Merge pull request #8 from kilobyteno/add-default-uvicorn-config
2 parents 85b7122 + 4154405 commit f8034f2

File tree

2 files changed

+124
-0
lines changed

2 files changed

+124
-0
lines changed

tests/test_konfig.py

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import logging
2+
3+
import pytest
4+
5+
from tunsberg.konfig import uvicorn_config
6+
7+
8+
class TestUvicornConfig:
9+
def test_default_config(self):
10+
log_lvl = logging.NOTSET
11+
config = uvicorn_config(log_level=log_lvl)
12+
assert config['version'] == 1
13+
assert not config['disable_existing_loggers']
14+
assert config['formatters']['default']['format'] == '%(asctime)s - %(levelname)s - %(name)s - %(message)s'
15+
assert config['handlers']['file']['class'] == 'logging.FileHandler'
16+
assert config['handlers']['file']['filename'] == 'uvicorn.log'
17+
assert config['handlers']['file']['formatter'] == 'default'
18+
assert config['handlers']['console']['class'] == 'logging.StreamHandler'
19+
assert config['handlers']['console']['formatter'] == 'default'
20+
assert config['loggers']['uvicorn']['handlers'] == ['file', 'console']
21+
assert config['loggers']['uvicorn']['level'] == logging.getLevelName(log_lvl)
22+
assert not config['loggers']['uvicorn']['propagate']
23+
assert config['loggers']['uvicorn.error']['handlers'] == ['file', 'console']
24+
assert config['loggers']['uvicorn.error']['level'] == logging.getLevelName(log_lvl)
25+
assert not config['loggers']['uvicorn.error']['propagate']
26+
assert config['loggers']['uvicorn.access']['handlers'] == ['file', 'console']
27+
assert config['loggers']['uvicorn.access']['level'] == logging.getLevelName(log_lvl)
28+
assert not config['loggers']['uvicorn.access']['propagate']
29+
30+
def test_invalid_log_level(self):
31+
with pytest.raises(ValueError):
32+
uvicorn_config(log_level=999)
33+
34+
def test_empty_log_format(self):
35+
with pytest.raises(ValueError):
36+
uvicorn_config(log_level=logging.NOTSET, log_format='')
37+
38+
def test_empty_log_file_path(self):
39+
with pytest.raises(ValueError):
40+
uvicorn_config(log_level=logging.NOTSET, log_file_path='')
41+
42+
def test_custom_log_format(self):
43+
log_format = '%(asctime)s - %(levelname)s - %(name)s - %(message)s - %(filename)s - %(lineno)s'
44+
config = uvicorn_config(log_level=logging.NOTSET, log_format=log_format)
45+
assert config['formatters']['default']['format'] == log_format
46+
47+
def test_custom_log_file_path(self):
48+
log_file_path = 'custom.log'
49+
config = uvicorn_config(log_level=logging.NOTSET, log_file_path=log_file_path)
50+
assert config['handlers']['file']['filename'] == log_file_path
51+
52+
def test_custom_log_level(self):
53+
log_lvl = logging.INFO
54+
config = uvicorn_config(log_level=log_lvl)
55+
assert config['loggers']['uvicorn']['level'] == logging.getLevelName(log_lvl)
56+
assert config['loggers']['uvicorn.error']['level'] == logging.getLevelName(log_lvl)
57+
assert config['loggers']['uvicorn.access']['level'] == logging.getLevelName(log_lvl)

tunsberg/konfig.py

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import logging
2+
3+
4+
def uvicorn_config(
5+
log_level: int = logging.DEBUG, log_file_path: str = 'uvicorn.log', log_format: str = '%(asctime)s - %(levelname)s - %(name)s - %(message)s'
6+
) -> dict:
7+
"""
8+
Generate a configuration dictionary for Uvicorn logging.
9+
10+
:param log_level: Log level integer
11+
:type log_level: int
12+
:param log_file_path: Path to the log file
13+
:type log_file_path: str
14+
:param log_format: Log format string
15+
:type log_format: str
16+
:return: Configuration dictionary
17+
:rtype: dict
18+
"""
19+
# Make sure the log level is valid
20+
if logging.getLevelName(log_level) is None or logging.getLevelName(log_level).__contains__('Level'):
21+
raise ValueError('Invalid log level')
22+
23+
# Make sure log format is not empty
24+
if not log_format:
25+
raise ValueError('Log format cannot be empty')
26+
27+
# Make sure log file path is not empty
28+
if not log_file_path:
29+
raise ValueError('Log file path cannot be empty')
30+
31+
return {
32+
'version': 1,
33+
'disable_existing_loggers': False,
34+
'formatters': {
35+
'default': {
36+
'format': log_format,
37+
},
38+
},
39+
'handlers': {
40+
'file': {
41+
'class': 'logging.FileHandler',
42+
'filename': log_file_path,
43+
'formatter': 'default',
44+
},
45+
'console': {
46+
'class': 'logging.StreamHandler',
47+
'formatter': 'default',
48+
},
49+
},
50+
'loggers': {
51+
'uvicorn': {
52+
'handlers': ['file', 'console'],
53+
'level': logging.getLevelName(log_level),
54+
'propagate': False,
55+
},
56+
'uvicorn.error': {
57+
'handlers': ['file', 'console'],
58+
'level': logging.getLevelName(log_level),
59+
'propagate': False,
60+
},
61+
'uvicorn.access': {
62+
'handlers': ['file', 'console'],
63+
'level': logging.getLevelName(log_level),
64+
'propagate': False,
65+
},
66+
},
67+
}

0 commit comments

Comments
 (0)