Maple Grove Report

Maple Grove Report

Subscribe to Our Newsletter

Get our latest articles delivered straight to your inbox. No spam, we promise.


If you’ve ever debugged a web application, you’ve probably done this more than you’d like to admit. An error pops up. You scroll through your logs. You find what looks important. You copy a chunk of it. Then you paste it somewhere. Maybe into a chat with a teammate, maybe into a document, or increasingly, into an AI tool to help you make sense of it.

I’ve been in your shoes, and at some point, I felt like this needed to stop. So, I carefully crafted a solution that takes care of this manual log handling.

Crafting an automation system for parsing logs

Letting a script handle manual workflow

Home Assistant C.A.F.E. automation flowchart editor integration. Credit: Tim Brookes / How-To Geek

Logs are already structured text. With a small script, I could pull out only the important parts, clean them up, and format them into something readable, automatically. The idea was simple: take the exact workflow I was repeating by hand, and turn it into something I could run with a single command. A reusable script.

To test this idea, I used a tiny demo web app that randomly throws errors and writes them to a log file. If you want to follow along, I’ve put the code up on my GitHub. But you don’t need this exact setup. Any application that writes logs to a file will work the same way. The only thing that matters for now is a growing log file with a mix of useful errors and some noise around them.

Instead of manually digging through logs every time, I wrote a small, smart Python script to do the boring part for me. The idea is simple: read the log file, pull out only the error sections, clean them up, and save them into a Markdown file I can use anywhere. Here’s a minimal version of the script:

from datetime import datetime

LOG_FILE = "app.log"


def is_new_log_entry(line):
    return any(level in line for level in ["INFO", "WARNING", "DEBUG", "ERROR"])


def extract_errors(lines):
    errors = []
    current_error = []
    capturing = False

    for line in lines:
        if "ERROR" in line:
            if current_error:
                errors.append("".join(current_error))
                current_error = []
            capturing = True

        elif capturing and is_new_log_entry(line):
            errors.append("".join(current_error))
            current_error = []
            capturing = False

        if capturing:
            current_error.append(line)

    if current_error:
        errors.append("".join(current_error))

    return errors


def format_markdown(errors):
    formatted = []

    for i, error in enumerate(errors, 1):
        block = f"### Error {i}\n```\n{error.strip()}\n```"
        formatted.append(block)

    return "\n".join(formatted)


def save_report(content):
    timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M")
    filename = f"error_report_{timestamp}.md"

    with open(filename, "w") as f:
        f.write("# Error Report\n")
        f.write(content)

    print(f"Saved: {filename}")


def main():
    with open(LOG_FILE, "r") as f:
        lines = f.readlines()

    errors = extract_errors(lines)

    if not errors:
        print("No errors found.")
        return

    report = format_markdown(errors)
    save_report(report)


if __name__ == "__main__":
    main()

There are four small steps happening here:

  1. Read the log file: The script loads the log file into memory as a list of lines. This makes it easier to process logs one step at a time instead of dealing with one big chunk of text.
  2. Extract only error logs: Whenever a line contains “ERROR”, the script treats that as the beginning of a new error block. From that point on, it starts collecting every line that belongs to that error, including the full traceback.
  3. Capture the full error block: Instead of guessing where the error ends, the script keeps collecting lines until it hits the start of a new log entry (like “INFO” or another “ERROR”.) This ensures you get the entire stack trace without cutting anything off.
  4. Format the output: Each error is wrapped in a clean Markdown block, making it easy to read, share, or paste into other tools.
  5. Save it with a timestamp: Finally, the script writes everything to a new file with a timestamped name, so you don’t overwrite previous reports:
error_report_2026-04-16_14-32.md
3D logos of Python and Microsoft Excel side by side on a blue and yellow background.


Python in Excel isn’t just for programmers—4 useful things you can do with it right now

Turn Excel into a lightweight data-science tool for cleaning datasets, standardizing dates, visualizing clusters, and analyzing keywords.

The result

What my workflow looks like with the script in action

After hitting the error endpoint a few times, my raw log file (app.log) looked like this:

2026-04-17 19:57:58,880 - INFO - Root endpoint was called
2026-04-17 19:58:17,147 - INFO - Root endpoint was called
2026-04-17 19:58:32,806 - INFO - Root endpoint was called
2026-04-17 19:58:42,878 - INFO - Error endpoint was called
2026-04-17 19:58:42,878 - ERROR - Exception occurred in /error endpoint
Traceback (most recent call last):
  File ".../main.py", line 28, in trigger_error
    result = 10 / 0
ZeroDivisionError: division by zero
2026-04-17 19:58:56,878 - INFO - Root endpoint was called
2026-04-17 19:58:59,833 - INFO - Root endpoint was called
2026-04-17 19:59:02,997 - INFO - Error endpoint was called
2026-04-17 19:59:02,997 - ERROR - Exception occurred in /error endpoint
Traceback (most recent call last):
  File ".../main.py", line 28, in trigger_error
    result = 10 / 0
ZeroDivisionError: division by zero
...
A log file showing different types of logs from a web application.

It’s a mix of everything: successful requests, repeated noise, and the actual errors buried in between. After running the script, I got a clean Markdown report:

# Error Report

### Error 1

```
2026-04-17 19:58:42,878 - ERROR - Exception occurred in /error endpoint
Traceback (most recent call last):
  File "D:\Content Writing\How-To Geek\automate logs\demo-webapp-error\main.py", line 28, in trigger_error
    result = 10 / 0
             ~~~^~~
ZeroDivisionError: division by zero
```
...
A clean Markdown file containing structured error outputs captured and cleaned from a log file.

Each error is isolated, complete, and already formatted in a way that’s easy to read or share.

Now, you can use this script and take the automation to the next level by integrating Slack, an LLM, or any other service where you’d want to copy and paste this log. That way, the logs will automatically reach where you want them to be.

Hands typing on a white keyboard, surrounded by floating Bash scripting code snippets and icons against a green background.


18 Bash string tricks that fix common scripting headaches

Unlock the power of Bash strings with these clever techniques.


Automation saves the day

This was a fun experiment, but it has changed my outlook towards scripting and automation. With such a simple but useful Python script, I was able to save hours of headache and manual work.

apple mac mini 2024 with m4 pro

Brand

Apple

Operating System

macOS




Source link


Android’s new notification rules could finally tame your alert overload. Early code in Android 17 points to a more capable way to manage how and when your phone interrupts you, especially if constant pings have started to feel overwhelming.

The system, spotted in Android 17 Beta 3 by Android Authority, shows you’ll be able to set custom behaviors for notifications based on specific apps or even individual contacts. Instead of muting everything, you’ll be able to decide what deserves attention and what can stay quiet in the background.

Android already has an edge in notification management. This upgrade builds on that lead by making alerts feel more tailored to your daily habits.

Five actions reshape how alerts behave

At the center of the system are five actions you can assign to notifications, each changing how alerts appear and interrupt you.

These include Silence, Block, Silence and Bundle, Highlight, and Highlight and Alert. Together, they give you control over both visibility and urgency, which current settings don’t fully offer.

That opens up practical use cases that go beyond simple muting. You could bundle less important updates from social apps while keeping work messages front and center, or block certain alerts entirely without affecting others. The flexibility feels intentional and grounded in real habits.

Why contact-level control stands out

The bigger shift is how this extends beyond apps to individual people. Right now, Android lets you adjust app behavior, but it doesn’t fully separate how different contacts are handled within the same space.

Strings of code also indicate you’ll be able to search and select contacts when building rules, then apply specific behaviors to them. That means you could silence one person’s calls without muting everyone else, which solves a common frustration.

There’s also a hint of prioritization. Highlighted alerts may appear more prominently or rise to the top, helping important messages stand out without constant manual sorting.

Early feature, but clear direction

There are still unknowns. Google hasn’t confirmed this for Android 17, and features found in early code don’t always make it to release. The teardown itself makes that clear.

Even so, the signs point to broader availability if it ships. The same strings appear in leaked One UI 9 builds, suggesting Samsung devices could support it as well.

If this rolls out, the benefit is practical. You’ll spend less time managing noise and more time focusing on what actually matters, which is exactly where notification systems need to go next.



Source link

Recent Reviews