Compare commits
2
Commits
05ce194478
...
4a1cd00e6e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a1cd00e6e | ||
|
|
df2765b16a |
@@ -4,9 +4,17 @@ skoda.conf
|
||||
*.conf
|
||||
secrets.conf
|
||||
|
||||
# Ausnahme von der Zeile darueber: hier stehen keine Zugangsdaten, sondern
|
||||
# die Rotationsregeln, und die gehoeren zum Betrieb wie die Startskripte.
|
||||
!logrotate.conf
|
||||
|
||||
# Protokolle. wattpilotshell.log ist allein 329 MB gross, die Logs machen
|
||||
# 93 Prozent des Verzeichnisses aus.
|
||||
*.log
|
||||
# Die rotierten Staende dazu - *.log.1, *.log.2.gz und so fort.
|
||||
*.log.*
|
||||
# Merkzettel von logrotate: wann welche Datei zuletzt dran war.
|
||||
logrotate.state
|
||||
|
||||
# Python
|
||||
__pycache__/
|
||||
|
||||
@@ -256,6 +256,14 @@ dieselbe Client-Kennung benutzen. Genau davor schützt das Beenden am Anfang.
|
||||
Ausgabe landet in `autoActions.log` neben `solarOutput.log`. `SIGTERM` fängt
|
||||
der Runner ab und fährt geordnet herunter.
|
||||
|
||||
Nachzulesen ist beides im Dashboard unter **Protokolle** — die Seite liest die
|
||||
Dateien direkt, filterbar nach Text und Level. Klein gehalten werden sie von
|
||||
`logs_rotieren.sh` samt `logrotate.conf` eine Ebene höher: täglich, vierzehn
|
||||
Stände, alles über 20 MB sofort. Weil die Prozesse monatelang durchlaufen,
|
||||
arbeitet die Rotation mit `copytruncate` — deshalb leiten die Startskripte mit
|
||||
`>>` um und nicht mehr mit `&>`. Wer das zurückdreht, bekommt nach der
|
||||
nächsten Rotation eine Logdatei, die vorn aus Nullbytes besteht.
|
||||
|
||||
`fetch_calendar.py` gehört einmal jährlich in den Cron:
|
||||
|
||||
```
|
||||
|
||||
@@ -138,16 +138,50 @@ class Regelwerk:
|
||||
@staticmethod
|
||||
def signatur_lesen(db):
|
||||
"""
|
||||
Woran der Runner merkt, dass er neu laden muss. `changed` allein
|
||||
genuegt nicht: eine geloeschte Automatik veraendert den groessten
|
||||
Zeitstempel nicht. Deshalb zaehlen die Zeilen mit - auch die der
|
||||
Geraetetabellen, damit ein Discovery-Lauf ebenfalls durchschlaegt.
|
||||
Woran der Runner merkt, dass er neu laden muss.
|
||||
|
||||
`changed` allein genuegt nicht: eine geloeschte Automatik veraendert
|
||||
den groessten Zeitstempel nicht. Die Zeilen zu zaehlen genuegt aber
|
||||
auch nicht - die Weboberflaeche speichert eine Automatik, indem sie
|
||||
deren Bedingungen und Aktionen loescht und gleich wieder einfuegt. Wer
|
||||
nur die Uhrzeit einer Bedingung verstellt, aendert damit weder die
|
||||
Zeilenzahl noch `changed`: ON UPDATE stoesst nur an, wenn sich in
|
||||
automations wirklich eine Spalte aendert, und Name, Stockwerk und
|
||||
Zeitfenster stehen ja noch genauso da. Der Runner lief dann bis zum
|
||||
naechsten Neustart mit der alten Uhrzeit weiter, ohne dass irgendwo
|
||||
etwas schieflief - er wusste es schlicht nicht besser.
|
||||
|
||||
Deshalb geht jetzt der Inhalt mit ein, als Summe der CRC32 je Zeile.
|
||||
Das ist kein Hash mit Sicherheitsanspruch, sondern ein billiger
|
||||
Fingerabdruck - er wird alle paar Sekunden gebildet und darf nichts
|
||||
kosten. Zwei Aenderungen, die sich in der Summe gegenseitig aufheben,
|
||||
sind theoretisch denkbar und praktisch nicht zu erwarten. Die
|
||||
Zeilenzahl steht trotzdem daneben, damit eine geloeschte und eine neu
|
||||
angelegte Zeile nicht zufaellig gleich viel ergeben.
|
||||
|
||||
Neu dabei sind die Aktionsparameter. Sie standen vorher gar nicht
|
||||
drin: eine geaenderte Zielhoehe einer Jalousie schlug also ebenso
|
||||
wenig durch.
|
||||
|
||||
Die Zeilenzahlen der Geraetetabellen bleiben, damit ein
|
||||
Discovery-Lauf weiterhin ein Neuladen ausloest.
|
||||
"""
|
||||
with db.cursor() as c:
|
||||
c.execute("""SELECT (SELECT COUNT(*) FROM automations) AS a,
|
||||
(SELECT UNIX_TIMESTAMP(MAX(changed)) FROM automations) AS t,
|
||||
(SELECT COUNT(*) FROM automation_conditions) AS b,
|
||||
(SELECT COALESCE(SUM(CRC32(CONCAT_WS(':',
|
||||
id, automation_id, group_no, position,
|
||||
state_id, operator, value))), 0)
|
||||
FROM automation_conditions) AS bs,
|
||||
(SELECT COUNT(*) FROM automation_actions) AS c,
|
||||
(SELECT COALESCE(SUM(CRC32(CONCAT_WS(':',
|
||||
id, automation_id, position, command_id))), 0)
|
||||
FROM automation_actions) AS cs,
|
||||
(SELECT COUNT(*) FROM automation_action_params) AS p,
|
||||
(SELECT COALESCE(SUM(CRC32(CONCAT_WS(':',
|
||||
action_id, parameter_id, value))), 0)
|
||||
FROM automation_action_params) AS ps,
|
||||
(SELECT COUNT(*) FROM actor_states) AS d,
|
||||
(SELECT COUNT(*) FROM actor_commands) AS e""")
|
||||
return tuple(sorted(c.fetchone().items()))
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
# Rotation der Logdateien des SolarManagers.
|
||||
#
|
||||
# Aufgerufen wird das ueber logs_rotieren.sh, einmal taeglich aus dem
|
||||
# Aufgabenplaner. Nicht in /etc/logrotate.d abgelegt: das ist DSM-Gebiet und
|
||||
# waere beim naechsten Systemupdate weg. Hier steht es neben den Prozessen,
|
||||
# zu denen es gehoert, und liegt im selben Repository.
|
||||
#
|
||||
# copytruncate ist der Kern der Sache. Die Prozesse laufen monatelang durch
|
||||
# und halten ihre Logdatei offen; niemand will sie fuer eine Rotation neu
|
||||
# starten. Also wird der Inhalt weggeschrieben und die Datei geleert, statt
|
||||
# sie umzubenennen - der Prozess merkt nichts davon. Voraussetzung ist, dass
|
||||
# die Startskripte mit ">>" umleiten und nicht mit "&>", sonst schreibt der
|
||||
# Prozess nach dem Leeren an seiner alten Stelle weiter und die Datei
|
||||
# bekommt ein Loch aus Nullbytes. Genau deshalb wurde das dort umgestellt.
|
||||
#
|
||||
# Der Preis von copytruncate sind die Zeilen, die zwischen Kopieren und
|
||||
# Leeren hereinkommen - die gehen verloren. Bei einem Betriebslog ist das
|
||||
# der guenstigere Handel.
|
||||
|
||||
/volume1/homes/wagner/SolarManager/solarOutput.log
|
||||
/volume1/homes/wagner/SolarManager/autoActions.log
|
||||
/volume1/homes/wagner/SolarManager/wattpilotshell.log
|
||||
/volume1/homes/wagner/SolarManager/wsMQTTbridge.log
|
||||
/volume1/homes/wagner/SolarManager/wecker.log
|
||||
{
|
||||
daily
|
||||
# Zwei Wochen zurueck. Weiter zurueck hat noch nie jemand gesucht, und
|
||||
# was aelter ist, steht ohnehin als Messwert in der Datenbank.
|
||||
rotate 14
|
||||
# Zusaetzlich zur Tagesgrenze: was ueber 20 MB geht, wird sofort
|
||||
# rotiert. Sonst koennte ein Prozess, der in eine Fehlerschleife
|
||||
# geraet, an einem einzigen Tag das Volume fuellen.
|
||||
maxsize 20M
|
||||
compress
|
||||
# Eine leere Datei zu rotieren bringt nichts ausser vierzehn leeren
|
||||
# Archiven - der Wecker meldet an den meisten Tagen gar nichts.
|
||||
notifempty
|
||||
# Fehlt eine Datei, ist das kein Fehler: nicht jeder Prozess laeuft
|
||||
# auf jedem System.
|
||||
missingok
|
||||
copytruncate
|
||||
}
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
# Rotiert die Logdateien des SolarManagers.
|
||||
#
|
||||
# Gehoert einmal taeglich in den Aufgabenplaner (Benutzer wagner genuegt,
|
||||
# root ist nicht noetig - alle Dateien gehoeren wagner). Die Regeln stehen in
|
||||
# logrotate.conf daneben.
|
||||
#
|
||||
# Der Zustand kommt ausdruecklich nicht aus /var/lib/logrotate: dort liegt
|
||||
# der von DSM, und ein zweiter Aufrufer haette sich dort mit dem System in
|
||||
# die Quere gebracht. Die eigene Datei bleibt unter unserer Kontrolle und
|
||||
# ist bei Bedarf einfach zu loeschen - dann faengt die Rotation von vorn an.
|
||||
#
|
||||
# Ein Lauf dauert ein bis zwei Minuten, auch wenn nichts zu tun ist. Das
|
||||
# liegt nicht an uns: Synologys logrotate zaehlt bei jedem Start erst den
|
||||
# Platzverbrauch unter /var/log zusammen und stolpert dabei ueber Ordner,
|
||||
# die wagner nicht lesen darf. Die Meldungen "Permission denied" von /bin/du
|
||||
# sind harmlos und gehoeren dazu.
|
||||
#
|
||||
# ./logs_rotieren.sh normaler Lauf
|
||||
# ./logs_rotieren.sh -f sofort rotieren, auch wenn noch nichts faellig
|
||||
# ./logs_rotieren.sh -d nur zeigen, was passieren wuerde
|
||||
|
||||
BASIS="/volume1/homes/wagner/SolarManager"
|
||||
|
||||
exec /usr/bin/logrotate \
|
||||
--state "$BASIS/logrotate.state" \
|
||||
"$@" \
|
||||
"$BASIS/logrotate.conf"
|
||||
Regular → Executable
+5
-1
@@ -16,4 +16,8 @@ fi
|
||||
|
||||
# Start the script
|
||||
cd "/volume1/homes/wagner/SolarManager/"
|
||||
/usr/bin/python3 "$SCRIPT_NAME" &> "$LOG_FILE" &
|
||||
# Angehaengt statt ueberschrieben: logrotate leert diese Datei mit
|
||||
# copytruncate, waehrend der Prozess sie offen haelt. Ohne Anhaengemodus
|
||||
# schriebe er danach an seiner alten Stelle weiter, und die Datei bekaeme ein
|
||||
# Loch aus Nullbytes in der Groesse des bisherigen Inhalts.
|
||||
/usr/bin/python3 "$SCRIPT_NAME" >> "$LOG_FILE" 2>&1 &
|
||||
Regular → Executable
+7
-1
@@ -46,7 +46,13 @@ beenden() {
|
||||
starte() {
|
||||
beenden "$1"
|
||||
echo "Starte $1, Ausgabe nach $2"
|
||||
"$PYTHON" "$1" &> "$2" &
|
||||
# Angehaengt, nicht ueberschrieben. Zwei Gruende: nach einem Neustart
|
||||
# will man sehen, warum der alte Lauf aufgehoert hat, und logrotate
|
||||
# arbeitet hier mit copytruncate - es leert die Datei, waehrend der
|
||||
# Prozess sie offen haelt. Beim Ueberschreiben stuende dessen
|
||||
# Schreibmarke danach weit hinten, und die Datei bekaeme ein Loch aus
|
||||
# Nullbytes in der Groesse des bisherigen Inhalts.
|
||||
"$PYTHON" "$1" >> "$2" 2>&1 &
|
||||
}
|
||||
|
||||
starte "solarManager.py" "solarOutput.log"
|
||||
|
||||
Regular → Executable
+7
-1
@@ -42,4 +42,10 @@ fi
|
||||
|
||||
# Start the script
|
||||
cd "$BASIS"
|
||||
/var/services/homes/wagner/.local/bin/wattpilotshell server &> "$LOG_FILE" &
|
||||
# Angehaengt statt ueberschrieben: logrotate leert diese Datei mit
|
||||
# copytruncate, waehrend der Prozess sie offen haelt. Ohne Anhaengemodus
|
||||
# schriebe er danach an seiner alten Stelle weiter, und die Datei bekaeme ein
|
||||
# Loch aus Nullbytes in der Groesse des bisherigen Inhalts. Bei dieser Datei
|
||||
# faellt das besonders ins Gewicht - die wattpilotshell meldet einen
|
||||
# Verbindungsfehler im Sekundentakt und hatte es so auf 329 MB gebracht.
|
||||
/var/services/homes/wagner/.local/bin/wattpilotshell server >> "$LOG_FILE" 2>&1 &
|
||||
|
||||
Regular → Executable
+6
-1
@@ -16,4 +16,9 @@ fi
|
||||
|
||||
# Start the script
|
||||
cd "/volume1/homes/wagner/SolarManager/"
|
||||
/usr/bin/python3 "$SCRIPT_NAME" &> "$LOG_FILE" &
|
||||
# Angehaengt statt ueberschrieben. Dieses Skript laeuft jede Nacht um drei,
|
||||
# und mit "&>" war die Datei danach jedes Mal leer - was der Wecker am
|
||||
# Vortag gemeldet hat, war morgens nicht mehr nachzulesen. Ausserdem braucht
|
||||
# logrotate den Anhaengemodus: es leert die Datei mit copytruncate, waehrend
|
||||
# der Prozess sie offen haelt.
|
||||
/usr/bin/python3 "$SCRIPT_NAME" >> "$LOG_FILE" 2>&1 &
|
||||
Reference in New Issue
Block a user