Skip to content

Commit 9f852a4

Browse files
Create function, endpoint, frontend implementation for log persistence
Update CHANGELOG.md Lint ctrl.py Add persist_logs bool and integrate throughout the config flow Add many logger.info chunks for testing Add more logic to persist_logs toggle endpoint Change how default value is handled Change default permissions of journald.conf Fix spelling errors, add logger on frontend Move toggle_log_persistance away from FastAPI and towards the Api object Linting Call reinit at end of log toggle, reword models.py description of persist_logs Remove all uses of persist_logs from amplipi core, move to updater side Remove lingering changes from app.py, ctrl.py pylint pylint (2)
1 parent 96d41fc commit 9f852a4

4 files changed

Lines changed: 98 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
* Move system state out of running software directory
3838
* Fix updates on systems with an API password set
3939
* Fix the display service on systems with an API password set
40+
* Add toggleable option to persist logs
4041
* Streams
4142
* File Players can be temporary. A temporary File Player will remove itself from the list of available streams once disconnected from all sources.
4243
* File Players run their own Python container process similar to Internet Radio Stations, rather than running a cvlc command.

amplipi/ctrl.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ def reinit(self, settings: models.AppSettings = models.AppSettings(), change_not
220220
except Exception as exc:
221221
logger.exception("Error setting is_streamer flag: {exc}")
222222

223-
# determine if we're in LMS mode, based on a file
223+
# determine if we're in LMS mode, based on a file existing
224224
lms_mode_path = Path(defaults.USER_CONFIG_DIR, 'lms_mode')
225225
if lms_mode_path.exists():
226226
logger.info("lms mode")

amplipi/updater/asgi.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@
3636
import shutil
3737
import asyncio
3838

39+
import configparser
40+
from typing import Optional
41+
3942
# web framework
4043
import requests
4144
from fastapi import FastAPI, Request, File, UploadFile, Depends, APIRouter, Response
@@ -95,6 +98,69 @@ class ReleaseInfo(BaseModel):
9598
logger.exception(f'Error loading identity file: {e}')
9699

97100

101+
@router.get("/settings/persist_logs")
102+
def get_log_persist_state():
103+
conf_path = '/etc/systemd'
104+
config = configparser.ConfigParser(strict=False, allow_no_value=True)
105+
config.read(f'{conf_path}/journald.conf')
106+
return config.get("Journal", "Storage", fallback="") == "persistent"
107+
108+
109+
@router.post("/settings/persist_logs")
110+
def toggle_persist_logs(value: Optional[bool] = None):
111+
"""
112+
Toggles the option within journald to save logs to memory or storage.
113+
Accepts an option bool called "value" for if you wish to change the value to a specific option rather than simply flip the state of the config file
114+
"""
115+
try:
116+
conf_path = '/etc/systemd'
117+
config = configparser.ConfigParser(strict=False, allow_no_value=True)
118+
config.read(f'{conf_path}/journald.conf')
119+
120+
if 'Journal' not in config:
121+
config.add_section('Journal')
122+
123+
# goal_value is a holdover from when this setting was in app.py and toggled via the config settings page
124+
# the bool is true if you wish to turn persistent logging on and false if you wish to turn it off
125+
# It can be set either with the optional arg of the function or it attempts to find the current value from the config file and set the opposite of that
126+
goal_value: bool
127+
if value is not None:
128+
goal_value = value
129+
else:
130+
goal_value = not get_log_persist_state()
131+
132+
if goal_value: # Set persist
133+
config.set('Journal', 'Storage', 'persistent')
134+
config.set('Journal', 'SyncIntervalSec', '30s')
135+
config.set('Journal', 'SystemMaxUse', '64M')
136+
137+
config.remove_option('Journal', 'RuntimeMaxUse')
138+
config.remove_option('Journal', 'ForwardToConsole')
139+
config.remove_option('Journal', 'ForwardToWall')
140+
141+
logger.info("persist_logs activated!")
142+
143+
else: # Reset config to default as seen in configure.py
144+
config.set('Journal', 'Storage', 'volatile')
145+
config.set('Journal', 'RuntimeMaxUse', '64M')
146+
config.set('Journal', 'ForwardToConsole', 'no')
147+
config.set('Journal', 'ForwardToWall', 'no')
148+
149+
config.remove_option('Journal', 'SyncIntervalSec')
150+
config.remove_option('Journal', 'SystemMaxUse')
151+
152+
logger.info("persist_logs deactivated!")
153+
154+
with open('/tmp/journald.conf.tmp', 'w', encoding="utf-8") as conf_file:
155+
config.write(conf_file)
156+
157+
subprocess.run(['sudo', 'mv', '/tmp/journald.conf.tmp', f'{conf_path}/journald.conf'], check=True)
158+
subprocess.run(['sudo', 'systemctl', 'restart', 'systemd-journald'], check=True)
159+
except Exception as exc:
160+
logger.error("persist_logs toggle failed!")
161+
raise exc
162+
163+
98164
@router.get('/update')
99165
def get_index():
100166
""" Get the update website """

amplipi/updater/static/index.html

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,20 +45,25 @@ <h1><span class="text-white">Ampli</span><span class="text-danger">Pi</span></h1
4545
<li class="nav-item">
4646
<a class="nav-link" id="set-password-tab" data-toggle="tab" href="#set-password" role="tab" aria-controls="set-password" aria-selected="false">Set Password</a>
4747
</li>
48+
<li class="nav-item">
49+
<a class="nav-link" id="admin-settings-tab" data-toggle="tab" href="#admin-settings" role="tab" aria-controls="admin-settings" aria-selected="false">Admin Settings</a>
50+
</li>
4851
<li class="nav-item">
4952
<a class="nav-link" id="support-tunnel-tab" data-toggle="tab" href="#support-tunnel" role="tab" aria-controls="support-tunnel" aria-selected="false">Support Tunnel</a>
5053
</li>
5154
</ul>
5255
</div>
5356
<div class="card-body text-center">
5457
<div class="tab-content" id="myTabContent">
58+
5559
<div class="tab-pane fade show active" id="latest-update" role="tabpanel" aria-labelledby="latest-update-tab">
5660
<div id='latest-update-name'>...</div>
5761
<div id='latest-update-desc' class="text-left"></div>
5862
<a id="submit-latest-update" role="button" class="btn btn-lg btn-primary text-center mt-3 d-none"
5963
onclick="ui_start_software_update($('#latest-update').attr('data-url'), $('#latest-update').attr('data-version'));">
6064
Start Update</a>
6165
</div>
66+
6267
<div class="tab-pane fade" id="older-update" role="tabpanel" aria-labelledby="older-update-tab">
6368
<select class="custom-select" id="older-update-sel" onchange="ui_select_release(this);">
6469
<!-- Releases populated from GH -->
@@ -69,12 +74,14 @@ <h1><span class="text-white">Ampli</span><span class="text-danger">Pi</span></h1
6974
onclick="ui_start_software_update($('#older-update-sel').val(), $('#older-update-sel').find(':selected').data('version'));">
7075
Start Update</a>
7176
</div>
77+
7278
<div class="tab-pane fade" id="manual-update" role="tabpanel" aria-labelledby="manual-update-tab">
7379
<div class="custom-file">
7480
<input id="update-file-selector" type="file" accept=".gz" onchange="$('#submit-custom-update').removeClass('disabled');">
7581
</div>
7682
<a id="submit-custom-update" role="button" class="btn btn-lg btn-primary text-center mt-3 disabled" onclick="ui_upload_software_update();">Start Update</a>
7783
</div>
84+
7885
<div class="tab-pane fade text-left" id="set-password" role="tabpanel" aria-labelledby="set-password-tab">
7986
<div class="set-password-dialog">
8087
This form allows you to set a password for the web interface. If the password fields are empty, it will unset the password protection. This will only set a password for the web interface, not the system password. This action will also log out any existing sessions.
@@ -87,6 +94,7 @@ <h1><span class="text-white">Ampli</span><span class="text-danger">Pi</span></h1
8794
</div>
8895
<a id="password" role="button" class="btn btn-lg btn-primary text-center mt-3" onClick="set_password();">Update Password</a>
8996
</div>
97+
9098
<div class="tab-pane fade text-left" id="support-tunnel" role="tabpanel" aria-labelledby="support-tunnel-tab">
9199
<div id="support-tunnel-dialog">
92100
This dialog allows you to request a support tunnel. Once requested, you must give the tunnel ID and preshared key to support, who can be reached via <a href="mailto:support@micro-nova.com">support@micro-nova.com</a>.
@@ -105,6 +113,28 @@ <h1><span class="text-white">Ampli</span><span class="text-danger">Pi</span></h1
105113
</div>
106114
</div>
107115
</div>
116+
117+
<div class="tab-pane fade text-left" id="admin-settings" role="tabpanel" aria-labelledby="admin-settings-tab">
118+
<script>
119+
async function getPersist(){
120+
const persist_logs = await fetch("/settings/persist_logs", { method: "GET" })
121+
let checkbox = document.getElementById("persist_logs_checkbox");
122+
checkbox.setAttribute("checked", persist_logs)
123+
}
124+
125+
async function setPersist(){
126+
const update_persist = await fetch("/settings/persist_logs", { method: "POST" })
127+
console.log(`persist_logs updated to ${update_persist}!`)
128+
}
129+
</script>
130+
<div id="admin-settings-dialog">
131+
This tab allows you to change settings relating to the core of AmpliPi, things that do not belong on the standard config page
132+
</div>
133+
<h6>WARNING: leaving log persistence on for extended periods can damage your system and void your warranty</h6>
134+
<input id="persist_logs_checkbox" type="checkbox" checked={persist_logs} onclick={setPersist()} />
135+
<label for="persist_logs_checkbox">Log Persistence</label>
136+
</div>
137+
108138
</div>
109139
</div>
110140
</div>

0 commit comments

Comments
 (0)