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 upload_logs command #309

Merged
merged 3 commits into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
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
97 changes: 87 additions & 10 deletions bot/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import re
import signal
import socket
import subprocess
import sys
import tarfile
import time
Expand All @@ -19,6 +20,7 @@
from apscheduler.events import EVENT_JOB_ERROR # type: ignore
from apscheduler.schedulers.background import BackgroundScheduler # type: ignore
import emoji
import requests
import telegram
from telegram import (
BotCommand,
Expand Down Expand Up @@ -324,25 +326,98 @@ def send_logs(update: Update, _: CallbackContext) -> None:
update.effective_message.bot.send_chat_action(chat_id=configWrap.secrets.chat_id, action=ChatAction.UPLOAD_DOCUMENT)
update.effective_message.reply_text(text=klippy.get_versions_info(), disable_notification=notifier.silent_commands, quote=True)
logs_list: List[Union[InputMediaAudio, InputMediaDocument, InputMediaPhoto, InputMediaVideo]] = []
if Path(configWrap.bot_config.log_file).exists():
with open(configWrap.bot_config.log_file, "rb") as fh:
logs_list.append(InputMediaDocument(fh.read(), filename="telegram.log"))
if Path(f"{configWrap.bot_config.log_path}/klippy.log").exists():
with open(f"{configWrap.bot_config.log_path}/klippy.log", "rb") as fh:
logs_list.append(InputMediaDocument(fh.read(), filename="klippy.log"))
if Path(f"{configWrap.bot_config.log_path}/moonraker.log").exists():
with open(f"{configWrap.bot_config.log_path}/moonraker.log", "rb") as fh:
logs_list.append(InputMediaDocument(fh.read(), filename="moonraker.log"))
log_files_names: List[str] = ["telegram.log", "klippy.log", "moonraker.log", "crowsnest.log"]
for log_file in log_files_names:
if Path(f"{configWrap.bot_config.log_path}/{log_file}").exists():
with open(f"{configWrap.bot_config.log_path}/{log_file}", "rb") as fh:
logs_list.append(InputMediaDocument(fh.read(), caption="Upload logs to analyzer /upload_logs", filename=log_file))

if logs_list:
update.effective_message.reply_media_group(logs_list, disable_notification=notifier.silent_commands, quote=True)
else:
update.effective_message.reply_text(
text="No logs found in log_path",
text=f"No logs found in log_path `{configWrap.bot_config.log_path}`",
disable_notification=notifier.silent_commands,
quote=True,
)


def upload_logs(update: Update, _: CallbackContext) -> None:
if update.effective_message is None or update.effective_message.bot is None:
logger.warning("Undefined effective message or bot")
return

if Path(f"{configWrap.bot_config.log_path}/dmesg.txt").exists():
Path(f"{configWrap.bot_config.log_path}/dmesg.txt").unlink()

dmesg_res = subprocess.run(f"dmesg -T > {configWrap.bot_config.log_path}/dmesg.txt", shell=True, executable="/bin/bash", check=False, capture_output=True)
if dmesg_res.returncode != 0:
logger.warning("dmesg file creation error: %s %s", dmesg_res.stdout.decode("utf-8"), dmesg_res.stderr.decode("utf-8"))
update.effective_message.reply_text(
text=f'Dmesg log file creation error {dmesg_res.stderr.decode("utf-8")}',
disable_notification=notifier.silent_commands,
quote=True,
)
return

if Path(f"{configWrap.bot_config.log_path}/debug.txt").exists():
Path(f"{configWrap.bot_config.log_path}/debug.txt").unlink()

commands = [
"lsb_release -a",
"uname -a",
"find /dev/serial",
"find /dev/v4l",
"free -h",
"df -h",
"lsusb",
"systemctl status KlipperScreen",
"systemctl status klipper-mcu",
"ip --details --statistics link show dev can0",
]
for command in commands:
subprocess.run(
f'echo >> {configWrap.bot_config.log_path}/debug.txt;echo "{command}" >> {configWrap.bot_config.log_path}/debug.txt;{command} >> {configWrap.bot_config.log_path}/debug.txt',
shell=True,
executable="/bin/bash",
check=False,
)

files = ["/boot/config.txt", "/boot/cmdline.txt", "/boot/armbianEnv.txt", "/boot/orangepiEnv.txt", "/boot/BoardEnv.txt", "/boot/env.txt"]
with open(configWrap.bot_config.log_path + "/debug.txt", mode="a", encoding="utf-8") as debug_file:
for file in files:
if Path(file).exists():
debug_file.write(f"\n{file}\n")
with open(file, mode="r", encoding="utf-8") as file_obj:
debug_file.writelines(file_obj.readlines())

if Path(f"{configWrap.bot_config.log_path}/logs.tar.xz").exists():
Path(f"{configWrap.bot_config.log_path}/logs.tar.xz").unlink()

with tarfile.open(f"{configWrap.bot_config.log_path}/logs.tar.xz", "w:xz") as tar:
for file in ["telegram.log", "crowsnest.log", "moonraker.log", "klippy.log", "dmesg.txt", "debug.txt"]:
if Path(f"{configWrap.bot_config.log_path}/{file}").exists():
tar.add(Path(f"{configWrap.bot_config.log_path}/{file}"), arcname=file)

with open(f"{configWrap.bot_config.log_path}/logs.tar.xz", "rb") as log_archive_ojb:
resp = requests.post(url="https://coderus.openrepos.net/klipper_logs", files={"tarfile": log_archive_ojb}, allow_redirects=False, timeout=25)
if resp.ok:
logs_path = resp.headers["location"]
logger.info(logs_path)
update.effective_message.reply_text(
text=f"Logs are available at https://coderus.openrepos.net{logs_path}",
disable_notification=notifier.silent_commands,
quote=True,
)
else:
logger.error(resp.reason)
update.effective_message.reply_text(
text=f"Logs upload failed `{resp.reason}`",
disable_notification=notifier.silent_commands,
quote=True,
)


def restart_bot() -> None:
scheduler.shutdown(wait=False)
if ws_helper.websocket:
Expand Down Expand Up @@ -928,6 +1003,7 @@ def bot_commands() -> Dict[str, str]:
"cancel": "cancel printing",
"files": "list gcode files. you can start printing one from menu",
"logs": "get klipper, moonraker, bot logs",
"upload_logs": "get klipper, moonraker, bot logs and upload logs to the analyzer https://coderus.openrepos.net/klipper_logs",
"macros": "list all visible macros from klipper",
"gcode": 'run any gcode command, spaces are supported. "gcode G28 Z"',
"video": "will take mp4 video from camera",
Expand Down Expand Up @@ -1057,6 +1133,7 @@ def start_bot(bot_token, socks):
dispatcher.add_handler(CommandHandler("macros", get_macros, run_async=True))
dispatcher.add_handler(CommandHandler("gcode", exec_gcode, run_async=True))
dispatcher.add_handler(CommandHandler("logs", send_logs, run_async=True))
dispatcher.add_handler(CommandHandler("upload_logs", upload_logs, run_async=True))

dispatcher.add_handler(MessageHandler(Filters.command, macros_handler, run_async=True))

Expand Down
4 changes: 3 additions & 1 deletion bot/notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,9 @@ def _notify(self, message: str, silent: bool, group_only: bool = False, manual:
photo.close()

# manual notification methods
def send_error(self, message: str) -> None:
def send_error(self, message: str, logs_upload: bool = False) -> None:
if logs_upload:
message += "\n Upload logs to analyzer /upload_logs"
self._sched.add_job(
self._send_message,
kwargs={
Expand Down
6 changes: 3 additions & 3 deletions bot/websocket_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ def parse_print_stats(self, message_params):
error_mess = f"Printer state change error: {print_stats_loc['state']}\n"
if "message" in print_stats_loc and print_stats_loc["message"]:
error_mess += f"{print_stats_loc['message']}\n"
self._notifier.send_error(error_mess)
self._notifier.send_error(error_mess, logs_upload=True)
elif state == "standby":
self._klippy.printing = False
self._notifier.remove_notifier_timer()
Expand Down Expand Up @@ -346,7 +346,7 @@ def websocket_to_message(self, ws_loc, ws_message):
state_message = message_result["state_message"]
if self._klippy.state_message != state_message and klippy_state != "startup":
self._klippy.state_message = state_message
self._notifier.send_error(f"Klippy changed state to {self._klippy.state}\n{self._klippy.state_message}")
self._notifier.send_error(f"Klippy changed state to {self._klippy.state}\n{self._klippy.state_message}", logs_upload=True)
else:
logger.error("UnKnown klippy state: %s", klippy_state)
self._klippy.connected = False
Expand All @@ -365,7 +365,7 @@ def websocket_to_message(self, ws_loc, ws_message):
return

if "error" in json_message:
self._notifier.send_error(f"{json_message['error']['message']}")
self._notifier.send_error(f"{json_message['error']['message']}", logs_upload=True)

else:
message_method = json_message["method"]
Expand Down
6 changes: 6 additions & 0 deletions scripts/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,11 @@ install_packages() {
sudo apt-get install --yes ${PKGLIST}
}

fix_permissions()}{
sudo echo "kernel.dmesg_restrict = 0" > /etc/sysctl.d/51-dmesg-restrict.conf
sudo sysctl kernel.dmesg_restrict=0
}

create_virtualenv() {
report_status "Installing python virtual environment..."

Expand Down Expand Up @@ -196,6 +201,7 @@ install_instances(){
sudo systemctl stop moonraker-telegram-bot*
status_msg "Installing dependencies"
install_packages
fix_permissions
create_virtualenv

init_config_path
Expand Down