From e27cc995f6d0ca2b3b12f7e98465fae8d09df882 Mon Sep 17 00:00:00 2001 From: Floke Date: Tue, 6 Jan 2026 20:40:04 +0000 Subject: [PATCH] docs(duckdns): Update status and sync to Notion - Added analysis of latest DNS monitor logs (06.01.2026). - Refactored sync_docs_to_notion.py to be generic and support multiple files. --- duckdns_setup.md | 17 ++++++++ sync_docs_to_notion.py | 99 +++++++++++++++--------------------------- 2 files changed, 51 insertions(+), 65 deletions(-) diff --git a/duckdns_setup.md b/duckdns_setup.md index 2714b07f..1c035ef8 100644 --- a/duckdns_setup.md +++ b/duckdns_setup.md @@ -60,6 +60,23 @@ docker logs dns-monitor ``` Häufig verursacht durch DSL-Resyncs oder Paketverlust wegen der Stichleitung. +## Aktueller Status (06.01.2026) + +Basierend auf den Logs des `dns-monitor` (Stand 20:34 Uhr) ergibt sich folgendes Bild: + +### 1. Analyse der Log-Phasen +* **Vormittag/Nachmittag:** Sporadische `[ALERT]`-Meldungen. Die IP bei DuckDNS sprang kurzzeitig auf die veraltete Endung `.49` zurück, stabilisierte sich aber meist nach 5-10 Minuten wieder auf `.252`. +* **Kritische Phase (19:38 - 19:54 Uhr):** Ein 20-minütiger anhaltender Alert. Cloudflare (`CF`) lieferte hartnäckig die alte IP `.49`, obwohl die öffentliche IP (`Pub`) bereits `.252` war. Dies deutet auf eine verzögerte TTL-Aktualisierung oder einen "Zombie-Updater" im Netzwerk hin, der kurzzeitig erfolgreich war. +* **Stabilisierung (seit 19:59 Uhr):** Das System ist seit über 30 Minuten durchgehend im Status `[OK]`. Sowohl Cloudflare als auch die lokale Auflösung zeigen stabil auf die `.252`. + +### 2. Erkenntnisse +* **Netzwerk-Instabilität:** Die `[NETWORK_WAIT]` Einträge korrelieren mit den DSL-Sync-Problemen der FritzBox. In diesen Momenten ist keine DNS-Abfrage möglich (Paketverlust). +* **Local Cache Lag:** Die Spalte `Loc` (Lokale Auflösung) zeigt oft noch `Unresolved` oder die alte IP, wenn Cloudflare bereits korrekt ist. Dies bestätigt, dass der interne DNS-Cache der Synology/Docker-Umgebung deutlich träger reagiert als externe Server. + +### 3. Empfehlung +* **Beobachtung:** Da die Stabilisierung seit 19:59 Uhr anhält, scheint der neue DuckDNS-Token nun die Oberhand gewonnen zu haben. +* **Hardware:** Die physische DSL-Beeinträchtigung (Stichleitung 17m) bleibt das primäre Risiko für die `NETWORK_WAIT` Timeouts. + ## Dateien - `/app/docker-compose.yml`: Definition der Services. - `/app/dns-monitor/monitor.sh`: Das Shell-Skript für den Monitor-Container. \ No newline at end of file diff --git a/sync_docs_to_notion.py b/sync_docs_to_notion.py index e682d550..bcaee916 100644 --- a/sync_docs_to_notion.py +++ b/sync_docs_to_notion.py @@ -2,10 +2,10 @@ import requests import json import os import re +import sys TOKEN_FILE = 'notion_api_key.txt' PARENT_PAGE_ID = "2e088f42-8544-8024-8289-deb383da3818" -DOC_FILE = "notion_integration.md" def parse_markdown_to_blocks(md_content): blocks = [] @@ -15,25 +15,21 @@ def parse_markdown_to_blocks(md_content): code_content = [] for line in lines: - # Don't strip indentation for code blocks, but do for logic checks stripped = line.strip() - # Handle Code Blocks if stripped.startswith("```"): if in_code_block: - # End of code block blocks.append({ "object": "block", "type": "code", "code": { - "rich_text": [{"type": "text", "text": {"content": "\n".join(code_content)}}], + "rich_text": [{"type": "text", "text": {"content": '\n'.join(code_content)}}], "language": "plain text" } }) code_content = [] in_code_block = False else: - # Start of code block in_code_block = True continue @@ -44,52 +40,38 @@ def parse_markdown_to_blocks(md_content): if not stripped: continue - # Headings if line.startswith("# "): blocks.append({ "object": "block", "type": "heading_1", - "heading_1": { - "rich_text": [{"type": "text", "text": {"content": line[2:]}}] - } - }) + "heading_1": {"rich_text": [{"type": "text", "text": {"content": line[2:]}}]}} + ) elif line.startswith("## "): blocks.append({ "object": "block", "type": "heading_2", - "heading_2": { - "rich_text": [{"type": "text", "text": {"content": line[3:]}}] - } - }) + "heading_2": {"rich_text": [{"type": "text", "text": {"content": line[3:]}}]}} + ) elif line.startswith("### "): blocks.append({ "object": "block", "type": "heading_3", - "heading_3": { - "rich_text": [{"type": "text", "text": {"content": line[4:]}}] - } - }) - # List Items + "heading_3": {"rich_text": [{"type": "text", "text": {"content": line[4:]}}]}} + ) elif stripped.startswith("* ") or stripped.startswith("- "): content = stripped[2:] blocks.append({ "object": "block", "type": "bulleted_list_item", - "bulleted_list_item": { - "rich_text": [{"type": "text", "text": {"content": content}}] - } - }) - # Numbered List (Simple detection) + "bulleted_list_item": {"rich_text": [{"type": "text", "text": {"content": content}}]}} + ) elif re.match(r"^\d+\.", stripped): content = re.sub(r"^\d+\.\s*", "", stripped) blocks.append({ "object": "block", "type": "numbered_list_item", - "numbered_list_item": { - "rich_text": [{"type": "text", "text": {"content": content}}] - } - }) - # Tables (Very basic handling: convert to code block for preservation) + "numbered_list_item": {"rich_text": [{"type": "text", "text": {"content": content}}]}} + ) elif stripped.startswith("|"): blocks.append({ "object": "block", @@ -99,27 +81,28 @@ def parse_markdown_to_blocks(md_content): "language": "plain text" } }) - # Paragraphs else: blocks.append({ "object": "block", "type": "paragraph", - "paragraph": { - "rich_text": [{"type": "text", "text": {"content": line}}] - } - }) + "paragraph": {"rich_text": [{"type": "text", "text": {"content": line}}]}} + ) return blocks -def upload_doc(token): +def upload_doc(token, file_path): try: - with open(DOC_FILE, 'r') as f: + with open(file_path, 'r') as f: content = f.read() except FileNotFoundError: - print(f"Error: Could not find '{DOC_FILE}'") + print(f"Error: Could not find '{file_path}'") return - print(f"Parsing '{DOC_FILE}'...") + title = os.path.basename(file_path) + if content.startswith("# "): + title = content.split('\n')[0][2:].strip() + + print(f"Parsing '{file_path}'...") children_blocks = parse_markdown_to_blocks(content) url = "https://api.notion.com/v1/pages" @@ -132,45 +115,31 @@ def upload_doc(token): payload = { "parent": { "page_id": PARENT_PAGE_ID }, "properties": { - "title": [ - { - "text": { - "content": "📘 Notion Integration Dokumentation" - } - } - ] + "title": [{"text": {"content": f"📘 {title}"}}] }, - "children": children_blocks[:100] # Safe limit + "children": children_blocks[:100] } - print(f"Uploading to Notion under parent {PARENT_PAGE_ID}...") + print(f"Uploading '{title}' to Notion...") try: response = requests.post(url, headers=headers, json=payload) response.raise_for_status() - data = response.json() - print("\n=== SUCCESS ===") - print(f"Documentation uploaded!") - print(f"URL: {data.get('url')}") - - except requests.exceptions.HTTPError as e: - print(f"\n=== ERROR ===") - print(f"HTTP Error: {e}") - print(f"Response: {response.text}") + print(f"SUCCESS: {data.get('url')}") except Exception as e: - print(f"\n=== ERROR ===") - print(f"An error occurred: {e}") + print(f"ERROR: {e}") -def main(): +if __name__ == "__main__": + if len(sys.argv) < 2: + print("Usage: python sync_docs_to_notion.py ") + sys.exit(1) + try: with open(TOKEN_FILE, 'r') as f: token = f.read().strip() except FileNotFoundError: print(f"Error: Could not find '{TOKEN_FILE}'") - return + sys.exit(1) - upload_doc(token) - -if __name__ == "__main__": - main() \ No newline at end of file + upload_doc(token, sys.argv[1]) \ No newline at end of file