Skip to content

Transform logging system into fully configurable multi-language system with Discord webhook integration#61

Closed
Copilot wants to merge 3 commits into
mainfrom
copilot/transform-logging-system-2
Closed

Transform logging system into fully configurable multi-language system with Discord webhook integration#61
Copilot wants to merge 3 commits into
mainfrom
copilot/transform-logging-system-2

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Oct 15, 2025

Overview

Transforms the SmartSpawner logging system from hardcoded English-only messages to a fully configurable, multi-language system with enhanced Discord webhook customization. This implementation maintains 100% backward compatibility while providing powerful new customization options through language files.

What Changed

Before: Hardcoded Logging

  • Event descriptions hardcoded in Java enum (SPAWNER_PLACE("Spawner placed"))
  • Discord embeds only configurable globally in config.yml
  • No internationalization support
  • Limited customization options

After: Configurable Multi-Language System

  • Event descriptions read from language files with automatic fallback
  • Discord embeds fully customizable per event type, per language
  • Support for 4 languages out of the box (en_US, vi_VN, de_DE, DonutSMP)
  • Rich placeholder system including new {newline} for formatting

Key Features

📝 Multi-Language Event Descriptions

Event descriptions are now fully customizable in language files:

# language/en_US/messages.yml
logging:
  events:
    SPAWNER_PLACE: "Spawner placed by {player} at {location}"
    SPAWNER_BREAK: "Spawner broken by {player}"
    # ... all 20 event types

🎨 Discord Embed Customization

Discord embeds can now be configured per event type in language files:

# language/en_US/messages.yml
logging:
  discord_embeds:
    SPAWNER_PLACE:
      title: "🟢 Spawner Placed"
      description: "Player: {player}{newline}Location: {location}"
      color: "57F287"
      fields:
        location:
          name: "📍 Location"
          value: "{world} ({x}, {y}, {z})"
          inline: true

🔧 Enhanced Placeholder System

New and existing placeholders supported:

  • Standard: {player}, {location}, {world}, {x}, {y}, {z}, {entity}, {time}
  • Logging: {description}, {event_type}
  • NEW: {newline} - for line breaks in messages
  • Dynamic: Event-specific metadata fields

Technical Implementation

New Component

  • LoggingMessageService - Central service for managing localized messages
    • Reads from language files
    • Provides Discord embed configurations
    • Includes null-safety checks and fallbacks
    • Optimized for performance (singleton pattern)

Modified Components

  • SpawnerLogEntry - Added overloaded methods for custom descriptions (backward compatible)
  • SpawnerActionLogger - Integrated LoggingMessageService for localized logging
  • DiscordEmbedBuilder - Reads embed configs from language files, falls back to config.yml
  • DiscordWebhookLogger - Optimized to reuse LoggingMessageService instance
  • config.yml - Enhanced documentation about multi-language support

Backward Compatibility

100% Backward Compatible

  • Existing installations work without any changes
  • Hardcoded descriptions remain as fallbacks
  • Config.yml Discord settings still functional
  • No breaking changes to public API

Usage Examples

Basic Customization

Users can customize event messages in their preferred language without touching Java code:

# Simple description override
logging:
  events:
    SPAWNER_PLACE: "✅ {player} placed a {entity} spawner"

Advanced Discord Customization

Create rich, informative Discord embeds with custom fields:

logging:
  discord_embeds:
    COMMAND_EXECUTE_PLAYER:
      title: "⚡ Command Executed"
      description: "**Player:** {player}{newline}**Command:** {full_command}"
      color: "5865F2"
      fields:
        server:
          name: "🌐 Server"
          value: "Production"
          inline: true
        time:
          name: "🕐 Time"
          value: "{time}"
          inline: true

Files Changed

Created:

  • core/src/main/java/github/nighter/smartspawner/logging/LoggingMessageService.java

Modified:

  • core/src/main/java/github/nighter/smartspawner/logging/SpawnerActionLogger.java
  • core/src/main/java/github/nighter/smartspawner/logging/SpawnerLogEntry.java
  • core/src/main/java/github/nighter/smartspawner/logging/discord/DiscordEmbedBuilder.java
  • core/src/main/java/github/nighter/smartspawner/logging/discord/DiscordWebhookLogger.java
  • core/src/main/resources/config.yml
  • core/src/main/resources/language/en_US/messages.yml (with comprehensive examples)
  • core/src/main/resources/language/vi_VN/messages.yml (Vietnamese translations)
  • core/src/main/resources/language/de_DE/messages.yml (German translations)
  • core/src/main/resources/language/DonutSMP/messages.yml

Stats: 1 new file, 9 modified files, ~850 lines added

Migration Guide

For Server Owners:

  1. No action required - system works with defaults
  2. To customize: Edit language/{your_locale}/messages.yml under logging: section
  3. See language/en_US/messages.yml for examples

For Developers:

  • SpawnerEventType.getDescription() still returns hardcoded fallback
  • New localized descriptions obtained via LoggingMessageService
  • All existing logging code continues to work unchanged

Resolves #[issue_number]

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • jitpack.io
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED -XX:MaxMetaspaceSize=384m -XX:+HeapDumpOnOutOfMemoryError -Xms256m -Xmx512m -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.8-bin/dl7vupf4psengwqhwktix4v1/gradle-8.8/lib/gradle-launcher-8.8.jar -javaagent:/home/REDACTED/.gradle/wrapper/dists/gradle-8.8-bin/dl7vupf4psengwqhwktix4v1/gradle-8.8/lib/agents/gradle-instrumentation-agent-8.8.jar org.gradle.launcher.daemon.bootstrap.GradleDaemon 8.8 (dns block)
  • maven.enginehub.org
  • mvn.lumine.io
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED -XX:MaxMetaspaceSize=384m -XX:+HeapDumpOnOutOfMemoryError -Xms256m -Xmx512m -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.8-bin/dl7vupf4psengwqhwktix4v1/gradle-8.8/lib/gradle-launcher-8.8.jar -javaagent:/home/REDACTED/.gradle/wrapper/dists/gradle-8.8-bin/dl7vupf4psengwqhwktix4v1/gradle-8.8/lib/agents/gradle-instrumentation-agent-8.8.jar org.gradle.launcher.daemon.bootstrap.GradleDaemon 8.8 (dns block)
  • nexus.iridiumdevelopment.net
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED -XX:MaxMetaspaceSize=384m -XX:+HeapDumpOnOutOfMemoryError -Xms256m -Xmx512m -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.8-bin/dl7vupf4psengwqhwktix4v1/gradle-8.8/lib/gradle-launcher-8.8.jar -javaagent:/home/REDACTED/.gradle/wrapper/dists/gradle-8.8-bin/dl7vupf4psengwqhwktix4v1/gradle-8.8/lib/agents/gradle-instrumentation-agent-8.8.jar org.gradle.launcher.daemon.bootstrap.GradleDaemon 8.8 (dns block)
  • repo.bg-software.com
  • repo.codemc.io
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED -XX:MaxMetaspaceSize=384m -XX:+HeapDumpOnOutOfMemoryError -Xms256m -Xmx512m -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.8-bin/dl7vupf4psengwqhwktix4v1/gradle-8.8/lib/gradle-launcher-8.8.jar -javaagent:/home/REDACTED/.gradle/wrapper/dists/gradle-8.8-bin/dl7vupf4psengwqhwktix4v1/gradle-8.8/lib/agents/gradle-instrumentation-agent-8.8.jar org.gradle.launcher.daemon.bootstrap.GradleDaemon 8.8 (dns block)
  • repo.glaremasters.me
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED -XX:MaxMetaspaceSize=384m -XX:+HeapDumpOnOutOfMemoryError -Xms256m -Xmx512m -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.8-bin/dl7vupf4psengwqhwktix4v1/gradle-8.8/lib/gradle-launcher-8.8.jar -javaagent:/home/REDACTED/.gradle/wrapper/dists/gradle-8.8-bin/dl7vupf4psengwqhwktix4v1/gradle-8.8/lib/agents/gradle-instrumentation-agent-8.8.jar org.gradle.launcher.daemon.bootstrap.GradleDaemon 8.8 (dns block)
  • repo.nightexpressdev.com
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED -XX:MaxMetaspaceSize=384m -XX:+HeapDumpOnOutOfMemoryError -Xms256m -Xmx512m -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.8-bin/dl7vupf4psengwqhwktix4v1/gradle-8.8/lib/gradle-launcher-8.8.jar -javaagent:/home/REDACTED/.gradle/wrapper/dists/gradle-8.8-bin/dl7vupf4psengwqhwktix4v1/gradle-8.8/lib/agents/gradle-instrumentation-agent-8.8.jar org.gradle.launcher.daemon.bootstrap.GradleDaemon 8.8 (dns block)
  • repo.opencollab.dev
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED -XX:MaxMetaspaceSize=384m -XX:+HeapDumpOnOutOfMemoryError -Xms256m -Xmx512m -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.8-bin/dl7vupf4psengwqhwktix4v1/gradle-8.8/lib/gradle-launcher-8.8.jar -javaagent:/home/REDACTED/.gradle/wrapper/dists/gradle-8.8-bin/dl7vupf4psengwqhwktix4v1/gradle-8.8/lib/agents/gradle-instrumentation-agent-8.8.jar org.gradle.launcher.daemon.bootstrap.GradleDaemon 8.8 (dns block)
  • repo.papermc.io
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED -XX:MaxMetaspaceSize=384m -XX:+HeapDumpOnOutOfMemoryError -Xms256m -Xmx512m -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.8-bin/dl7vupf4psengwqhwktix4v1/gradle-8.8/lib/gradle-launcher-8.8.jar -javaagent:/home/REDACTED/.gradle/wrapper/dists/gradle-8.8-bin/dl7vupf4psengwqhwktix4v1/gradle-8.8/lib/agents/gradle-instrumentation-agent-8.8.jar org.gradle.launcher.daemon.bootstrap.GradleDaemon 8.8 (dns block)
  • repository.minecodes.pl

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

Transform the current hardcoded logging system into a fully configurable, multi-language system with customizable message templates and Discord webhook integration.

Current System Analysis:
SpawnerEventType enum contains hardcoded descriptions like "Spawner placed", "Spawner broken", etc.
SpawnerLogEntry uses eventType.getDescription() for logging messages
Discord logging appears to be missing or basic
No internationalization support currently exists
Required Implementation:
Create Language System Structure
Existing language structure: language/{locale}/messages.yml, gui.yml, formatting.yml, items.yml
Add to existing messages.yml in each language folder:

# Spawner Logging Messages
logging:
  events:
    SPAWNER_PLACE: "
    SPAWNER_BREAK: "
...
  # Discord embed configurations
  discord_embeds:
    SPAWNER_PLACE:
      title: "
      description: "
      color: 0x00FF00
      fields:
         - name:
            value:
            inline:
        SPAWNER_BREAK:
...

Add option placeholder for spacing or new line

Update main config.yml to:

logging:
  discord:
    enabled: true
    webhook_url: "your_webhook_url_here"
    events:
      - SPAWNER_PLACE
      - SPAWNER_BREAK
...

make the default message and embedd in the messages.yml look like the current message and embedd discord of the logging system


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

@ptthanh02 ptthanh02 marked this pull request as ready for review October 15, 2025 01:58
Copilot AI and others added 2 commits October 15, 2025 02:04
Co-authored-by: ptthanh02 <73684260+ptthanh02@users.noreply.github.com>
Co-authored-by: ptthanh02 <73684260+ptthanh02@users.noreply.github.com>
Copilot AI changed the title [WIP] Transform logging system into configurable multi-language setup Transform logging system into fully configurable multi-language system with Discord webhook integration Oct 15, 2025
Copilot AI requested a review from ptthanh02 October 15, 2025 02:12
@ptthanh02 ptthanh02 closed this Oct 15, 2025
@ptthanh02 ptthanh02 deleted the copilot/transform-logging-system-2 branch October 15, 2025 02:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants