Poor man’s Datadog: Discord

I launched my side project on a rented server. My favourite logging method is console.log() (actually System.out.println(), but don’t tell anyone) followed by printing to a local .txt file. I wouldn’t wish Azure Monitor on my worst enemy.

This time neither would work, and here is the dumbest solution I could think of - and now you get to bask in its glory.

Just use a chat app - Discord, or Slack.
✅ Fast
✅ Free
✅ Easy
✅ One time setup

Would not recommend for general API logging/customer info, but if you need event/error logs and you get only a handful of these everyday - it works like a charm.

Setup

  1. Get the Discord webhook for the server (a secret URL that when called sends a message)
    Usually in serverintegrationscreate webhook, here are the docs
  2. Call the webhook in your code with the message/stack trace you want to send.
# Sample code
def _send_discord_message(*, message: str, message_type: str = "info", stacktrace: str | None = None):
    webhook_url = 'https://discord.com/api/webhooks/<your_webhook_link>'
    emoji = "📝" if message_type == "info" else "❌"
    
    # Format message
    full_message = f"{emoji} {message}"
    if stacktrace:
        full_message += f"\n```{stacktrace}```"
    
    # Max allowed len/message is 2000. Split into multiple messages if needed.
    MAX_CHARS_PER_MSG = 1500
    full_message_parts = [full_message[i:i + MAX_CHARS_PER_MSG] for i in range(0, len(full_message), MAX_CHARS_PER_MSG)]
    if len(full_message_parts) > 1:
        for i, part in enumerate(full_message_parts):
            full_message_parts[i] = f"{part} ({i + 1}/{len(full_message_parts)})"

    # Now shoot all those messages off
    for full_message_part in full_message_parts:
        payload = {"content": full_message_part}
        
        response = requests.post(webhook_url, json=payload)
        
        if response.status_code >= 200 and response.status_code < 300:
            print("✅ Message sent successfully!")
        else:
            print(f"❗ Failed to send message. Status code: {response.status_code}")

            # The message failed. It could be an issue with the content of the message
            # eg: contains unsupported chars/too long. 
            # To get notified in those cases, send a short, simple Discord message with the error message received.
            # Can't help if the cause is something else, like rate limiting though.
            payload = {"content": f"❗ Failed to send message. {response.text=}, {response.status_code=}"}
            requests.post(webhook_url, json=payload)

def discord_log(*, msg: str):
  """
  Post a normal message
  """
  _send_discord_message(message=msg, message_type="info")

def discord_error(*, msg: str, error: Exception | BaseException | None = None):
  """
  Post an error with a stack trace
  """
  stacktrace = None
  if error:
      stacktrace = str(error) + "".join(traceback.format_tb(error.__traceback__))
  _send_discord_message(message=msg, message_type="error", stacktrace=stacktrace)

And off to the races we go!