Class BugReportBundle

java.lang.Object
megamek.common.util.BugReportBundle

public class BugReportBundle extends Object
Collects the files a MegaMek bug report needs and writes them into a single zip archive that the player can attach to a GitHub issue.

The file list is a deliberate manifest rather than a directory scan. MegaMek's log directory also accumulates one gamelog*.html combat report per game and a Bot_*.mul unit list per bot per game, so a working installation can hold hundreds of megabytes there. Sweeping the directory wholesale would produce an archive far too large to attach, while a naive *.log filter would miss the combat report, which is usually the single most useful artifact in a MegaMek bug report.

The text logs and the combat reports can live in different directories. Log4j always writes the text logs to "logs" under the working directory, as set in mmconf/log4j2.xml, while the combat reports follow the player's log directory preference. The two are the same folder unless the player has relocated the reports.

The archive is capped at MAX_ARCHIVE_BYTES. Candidates are added in priority order and any that would push the total past the cap are skipped and named in the returned BugReportBundle.BundleResult, so the caller can tell the player exactly what was left out instead of silently truncating.

The version, OS, Java and hardware details are not a separate file. They are written into the live log just before packaging, so they sit in logs/megamek.log next to everything else, even when the startup header has rolled out of it.

Every text file passes through a BugReportRedactor on the way in, so the archive does not carry the player's home folder, login name, computer name or IP addresses. Save games and images are copied unchanged.

This class deliberately has no Swing or game-state dependencies so that it can be exercised headlessly.

See Also:
  • Field Details

    • MAX_ARCHIVE_BYTES

      public static final long MAX_ARCHIVE_BYTES
      GitHub refuses issue attachments larger than 25 MB, whatever the file type.
      See Also:
    • TEXT_LOG_DIRECTORY

      public static final String TEXT_LOG_DIRECTORY
      The directory Log4j writes the text logs to, relative to the working directory. Both MegaMek's and MekHQ's mmconf/log4j2.xml use it, so it holds MekHQ's logs too when MegaMek runs inside MekHQ.
      See Also:
  • Constructor Details

    • BugReportBundle

      public BugReportBundle(BugReportBundle.Sources sources)
      Creates a bundle description. Nothing is read from disk until writeTo(File) is called.
      Parameters:
      sources - where the report's files come from
    • BugReportBundle

      public BugReportBundle(BugReportBundle.Sources sources, @Nullable BugReportRedactor redactor)
      Creates a bundle description with a given redactor. Tests pass one built from fixed values; the game passes null, and a redactor for this machine is then built when the archive is written, off the event dispatch thread.
      Parameters:
      sources - where the report's files come from
      redactor - the redactor to clean text with, or null for one built from this machine
  • Method Details

    • writeTo

      public BugReportBundle.BundleResult writeTo(File archiveFile) throws IOException
      Writes the archive, adding candidates in priority order until the size cap is reached.

      Reaching the cap is not an error: remaining candidates are recorded as skipped and the archive is still completed, because a partial bundle is far more useful to a maintainer than none.

      Parameters:
      archiveFile - the zip file to create, overwriting any existing file at that path
      Returns:
      a description of what was written
      Throws:
      IOException - if the archive itself cannot be created or written
    • newestGameSummaryDirectory

      @Nullable public static File newestGameSummaryDirectory(File minimapDirectory)
      Finds the most recently changed game summary folder, for when there is no current game to name one. A game that crashed or was abandoned leaves its folder behind, and that is often the game the report is about.
      Parameters:
      minimapDirectory - the folder holding one sub-folder per game, normally gameSummaries/minimap
      Returns:
      the newest game folder, or null when there is none
    • asCurrentState

      public static String asCurrentState(String systemInformation)
      Rewords the startup header for logging mid-session. The header opens with "Starting MegaMek v...", which would read as a restart in the middle of a log.
      Parameters:
      systemInformation - the header from MegaMek.getUnderlyingInformation
      Returns:
      the same text without the leading "Starting "
    • addFileToArchive

      public static void addFileToArchive(File source, String entryName, ZipOutputStream zipOutputStream, BugReportRedactor redactor) throws IOException
      Adds one file to a bug report archive. Text files (logs, rolled .log.gz logs, combat reports, the game dataset) are redacted; everything else (saves, campaigns, images) is copied unchanged.

      Every suite archive goes through here, so MekHQ's bug report cleans its logs the same way MegaMek's does.

      Parameters:
      source - the file to add
      entryName - the path the file should occupy inside the archive; its ending decides whether it is redacted
      zipOutputStream - the open archive
      redactor - the redactor to clean text with
      Throws:
      IOException - if the archive itself cannot be written