Skip to content

Commit 341b77b

Browse files
committed
add logging
1 parent 4d7dc5e commit 341b77b

File tree

6 files changed

+173
-7
lines changed

6 files changed

+173
-7
lines changed

.env.example

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
PYTHON_LOG_LEVEL=DEBUG
2+
EMAIL_LOG_LEVEL=ERROR
3+
TELEGRAM_PYTHON_LOG_LEVEL=ERROR
4+
TELEGRAM_TOKEN=123456789:ABCDEFG_HIJKLMN_OPQ
5+
TELEGRAM_CHAT_ID=-87654321
6+
17
GITHUB_OAUTH_CLIENT_ID=changeme-get-from-github
28
GITHUB_OAUTH_CLIENT_SECRET=changeme-get-from-github
39
GITHUB_OAUTH_REDIRECT_URI="https://example.com/githubcallback"
@@ -8,3 +14,13 @@ SSH_PRIVATE_KEY=test
814
BASE_PATH=/home/username/path/
915
CONTAINER_HOSTING_SSH_SETUP_HANDLER_API_KEY=secret
1016
DOKKU_WRAPPER_FULL_PATH=/home/dokku/dokku-wrapper.py
17+
18+
LOGGING_STMP_MAILHOST_HOST=email.example.com
19+
LOGGING_SMTP_MAILHOST_PORT=25
20+
LOGGING_SMTP_FROMADDR=alerts@example.com
21+
LOGGING_SMTP_TOADDRS=alerts@example.com
22+
LOGGING_SMTP_SUBJECT="Log alert"
23+
LOGGING_SMTP_CREDENTIALS_EMAIL=alerts@example.com
24+
LOGGING_SMTP_CREDENTIALS_PASSWORD=changeme
25+
LOGGING_SMTP_SECURE=()
26+
LOGGING_SMTP_TIMEOUT=3

.flake8

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[flake8]
2+
ignore = E501

TelegramHTTPHandler.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from logging.handlers import HTTPHandler
2+
import requests
3+
4+
5+
class TelegramHTTPHandler(HTTPHandler):
6+
def __init__(self, *args, **kwargs):
7+
super().__init__(*args, **kwargs)
8+
9+
def emit(self, record):
10+
"""
11+
Emit log record to Telegram
12+
"""
13+
try:
14+
host = self.host
15+
if self.secure:
16+
scheme = "https://"
17+
else:
18+
scheme = "http://"
19+
url = self.url
20+
data = str(self.mapLogRecord(record))[
21+
0:4000
22+
] # Truncate to max Telegram message size
23+
url = f"{url}{data}"
24+
requests.get(scheme + host + "/" + url)
25+
except Exception:
26+
self.handleError(record)

app.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from starlette.responses import HTMLResponse
77
from starlette.requests import Request
88

9+
from logger import logger
910

1011
from cryptography.hazmat.primitives.asymmetric import rsa
1112
from cryptography.hazmat.primitives import serialization
@@ -23,6 +24,8 @@
2324
from dotenv import load_dotenv
2425
import subprocess
2526

27+
log = logger
28+
2629
load_dotenv(verbose=True)
2730

2831
templates = Jinja2Templates(directory="templates")
@@ -52,7 +55,7 @@ def amber_encrypt(key: str, value: str, amber_file_location="./amber.yaml"):
5255
def generate_ssh_keys():
5356
"""Generate public/private ssh keys
5457
55-
See also https://cryptography.io/en/latest/hazmat/primitives/asymmetric/rsa/
58+
See also https://cryptography.io/en/latest/hazmat/primitives/asymmetric/rsa/ # noqa: E501
5659
"""
5760
key = rsa.generate_private_key(
5861
public_exponent=65537,
@@ -90,9 +93,7 @@ def encrypt_github_secret(public_key: str, secret_value: str) -> str:
9093

9194
async def homepage(request):
9295
"""Homepage and display connect Github link"""
93-
body = await request.body()
94-
print(body)
95-
96+
log.debug("Homepage")
9697
client_id = GITHUB_OAUTH_CLIENT_ID
9798
state = f"{secrets.token_urlsafe(30)}---no-framework"
9899
state_rails = f"{secrets.token_urlsafe(30)}---rails"
@@ -181,7 +182,7 @@ async def githubcallback(request):
181182
"https://api.github.com/user/repos", headers=headers, data=json.dumps(data)
182183
)
183184
repo_url = req.json()["html_url"]
184-
print(repo_url)
185+
log.info(f"New container host started: {repo_url}")
185186

186187
# Create repo secrets
187188
req = requests.get(
@@ -197,7 +198,7 @@ def github_store_secret(SECRET_NAME, SECRET_VALUE: str):
197198
"encrypted_value": secret_Encrypted,
198199
"key_id": github_repo_public_key_id,
199200
}
200-
req = requests.put(
201+
req = requests.put( # noqa: 203
201202
f"https://api.github.com/repos/{username}/{repo_name}/actions/secrets/{SECRET_NAME}",
202203
headers=headers,
203204
data=json.dumps(data),
@@ -465,6 +466,8 @@ def github_store_secret(SECRET_NAME, SECRET_VALUE: str):
465466
origin = repo.remotes[0]
466467
repo.heads.main.set_tracking_branch(origin.refs.main)
467468
fetch = origin.fetch()[0]
469+
log.info(fetch)
470+
log.info("Oh no")
468471

469472
# Commit amber.yaml secrets file to repo
470473
index = repo.index
@@ -532,7 +535,8 @@ async def blog(request):
532535

533536

534537
async def health(request):
535-
print(request)
538+
log.debug(request)
539+
log.error("Testing error logging is working")
536540
return PlainTextResponse("OK")
537541

538542

logger.py

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import logging
2+
import coloredlogs
3+
from logging.handlers import QueueHandler, QueueListener, SMTPHandler
4+
from TelegramHTTPHandler import TelegramHTTPHandler
5+
import os
6+
import sys
7+
import queue
8+
from dotenv import load_dotenv
9+
10+
load_dotenv(verbose=True)
11+
12+
LOGGING_SMTP_MAILHOST_PORT = int(os.getenv("LOGGING_SMTP_MAILHOST_PORT"))
13+
LOGGING_SMTP_MAILHOST_HOST = os.getenv("LOGGING_SMTP_MAILHOST_HOST")
14+
LOGGING_SMTP_MAILHOST = (LOGGING_SMTP_MAILHOST_HOST, LOGGING_SMTP_MAILHOST_PORT)
15+
LOGGING_SMTP_FROMADDR = os.getenv("LOGGING_SMTP_FROMADDR")
16+
LOGGING_SMTP_TOADDRS = os.getenv("LOGGING_SMTP_TOADDRS")
17+
LOGGING_SMTP_SUBJECT = os.getenv("LOGGING_SMTP_SUBJECT")
18+
LOGGING_SMTP_CREDENTIALS_EMAIL = os.getenv("LOGGING_SMTP_CREDENTIALS_EMAIL")
19+
LOGGING_SMTP_CREDENTIALS_PASSWORD = os.getenv("LOGGING_SMTP_CREDENTIALS_PASSWORD")
20+
LOGGING_SMTP_CREDENTIALS = (
21+
LOGGING_SMTP_CREDENTIALS_EMAIL,
22+
LOGGING_SMTP_CREDENTIALS_PASSWORD,
23+
)
24+
LOGGING_SMTP_SECURE = os.getenv("LOGGING_SMTP_SECURE")
25+
if LOGGING_SMTP_SECURE == "()":
26+
LOGGING_SMTP_SECURE = ()
27+
else:
28+
LOGGING_SMTP_SECURE = None
29+
30+
LOGGING_SMTP_TIMEOUT = int(os.getenv("LOGGING_SMTP_TIMEOUT"))
31+
32+
33+
PYTHON_LOG_LEVEL = os.getenv("PYTHON_LOG_LEVEL", "DEBUG")
34+
TELEGRAM_PYTHON_LOG_LEVEL = os.getenv("TELEGRAM_PYTHON_LOG_LEVEL", "ERROR")
35+
EMAIL_LOG_LEVEL = os.getenv("EMAIL_LOG_LEVEL", "ERROR")
36+
37+
logger = logging.getLogger()
38+
handler = logging.StreamHandler() # sys.stderr will be used by default
39+
40+
41+
class RequestFormatter(coloredlogs.ColoredFormatter):
42+
def format(self, record):
43+
record.url = None
44+
record.remote_addr = None
45+
46+
return super().format(record)
47+
48+
49+
formatter = RequestFormatter(
50+
"[%(asctime)s] %(remote_addr)s requested %(url)s %(name)-12s %(levelname)-8s %(message)s %(funcName)s %(pathname)s:%(lineno)d" # noqa
51+
)
52+
53+
handler.setFormatter(formatter)
54+
handler.setLevel(
55+
PYTHON_LOG_LEVEL
56+
) # Both loggers and handlers have a setLevel method noqa: E501
57+
logger.addHandler(handler)
58+
logger.setLevel(PYTHON_LOG_LEVEL)
59+
60+
61+
# Log all uncuaght exceptions
62+
def handle_exception(exc_type, exc_value, exc_traceback):
63+
if issubclass(exc_type, KeyboardInterrupt):
64+
sys.__excepthook__(exc_type, exc_value, exc_traceback)
65+
return
66+
67+
logger.critical(
68+
"Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback)
69+
) # noqa: E501
70+
71+
72+
sys.excepthook = handle_exception
73+
74+
75+
# Telegram logging
76+
if os.getenv("APP_ENV", None) != "development":
77+
# See https://docs.python.org/3/howto/logging-cookbook.html#dealing-with-handlers-that-block # noqa
78+
que = queue.Queue(-1) # no limit on size
79+
queue_handler = QueueHandler(que)
80+
81+
telegram_token = os.getenv("TELEGRAM_TOKEN", None)
82+
telegram_chat_id = os.getenv("TELEGRAM_CHAT_ID", None)
83+
telegramHandlerHost = "api.telegram.org"
84+
85+
telegramHandlerUrl = (
86+
f"bot{telegram_token}/sendMessage?chat_id={telegram_chat_id}&text="
87+
)
88+
89+
telegramHandler = TelegramHTTPHandler(
90+
telegramHandlerHost, url=telegramHandlerUrl, secure=True
91+
)
92+
logger.info(
93+
f"Setting TELEGRAM_PYTHON_LOG_LEVEL to {TELEGRAM_PYTHON_LOG_LEVEL}"
94+
) # noqa: E501
95+
telegramHandler.setLevel(TELEGRAM_PYTHON_LOG_LEVEL)
96+
listener = QueueListener(que, telegramHandler, respect_handler_level=True)
97+
logger.addHandler(queue_handler)
98+
listener.start()
99+
100+
SMTP_log_que = queue.Queue(-1) # no limit on size
101+
SMTP_queue_handler = QueueHandler(SMTP_log_que)
102+
103+
smtpHandler = SMTPHandler(
104+
LOGGING_SMTP_MAILHOST,
105+
LOGGING_SMTP_FROMADDR,
106+
LOGGING_SMTP_TOADDRS,
107+
LOGGING_SMTP_SUBJECT,
108+
LOGGING_SMTP_CREDENTIALS,
109+
LOGGING_SMTP_SECURE,
110+
LOGGING_SMTP_TIMEOUT,
111+
)
112+
smtpHandler.setFormatter(formatter)
113+
smtpHandler.setLevel(EMAIL_LOG_LEVEL)
114+
SMTP_listener = QueueListener(SMTP_log_que, smtpHandler, respect_handler_level=True)
115+
116+
logger.addHandler(SMTP_queue_handler)
117+
SMTP_listener.start()

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ bcrypt
77
cryptography
88
PyNaCl
99
GitPython
10+
coloredlogs

0 commit comments

Comments
 (0)