Java日志轮转与数量限制:Game类配置及Log4j选型咨询
Hi Viola, let's break down your problem step by step—first addressing whether you need Log4j, then fixing your current java.util.logging (JUL) setup to limit log entries, and tying it to your log.properties file.
Short answer: You don't have to, but it will make your life easier if you need flexible log rules.
Your current code uses Java's built-in JUL, which can handle entry limits with a bit of custom code. But if you want native support for entry-count-based rolling, richer formatting, or easier configuration down the line, Log4j 2 is a far more robust tool. Let's cover both approaches starting with your existing setup.
First, a critical note: Your log.properties has a misunderstanding. The java.util.logging.FileHandler.limit=2 setting controls byte size per log file, not the number of log entries. That's why your config isn't limiting logs to 2 entries.
Step 1: Update log.properties
Adjust the config to avoid byte-based truncation, and add a custom property for your entry limit:
handlers = java.util.logging.FileHandler, java.util.logging.ConsoleHandler .level = ALL # File Logging java.util.logging.FileHandler.pattern=./logs/Marbles_game.log java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter java.util.logging.FileHandler.level=INFO java.util.logging.FileHandler.count=1 # Set a large limit to avoid byte-based cuts java.util.logging.FileHandler.limit=10485760 # Custom property for max log entries game.max.log.entries=2 # Console Logging java.util.logging.ConsoleHandler.level = OFF
Step 2: Modify the Game Class to Enforce Entry Limits
Add a counter to track log entries, load the limit from your config, and gate log writes:
import java.util.Random; import java.util.logging.Logger; import java.util.logging.Level; public class Game { public static final int numOfFutMarbles = 3; // przyszle kulki private int score; Field fieldProcessor = new Field(); Wave wave = new Wave(); Logger logger = Logger.getLogger(Game.class.getName()); Random random = new Random(); public final static int width = 9; // rozmiar planszy public final static int height = 9; public Bin[][] field; public static final int not_sel = -1; int activeBinX = not_sel; int activeBinY = not_sel; // New: Track log entries and load max limit from config private static final int MAX_LOG_ENTRIES; private int logEntryCount = 0; static { // Pull the limit from system properties (we'll pass this on startup) String maxLogsProp = System.getProperty("game.max.log.entries", "2"); MAX_LOG_ENTRIES = Integer.parseInt(maxLogsProp); } public Game() { this.field = new Bin[width][height]; for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { field[i][j] = new Bin(i, j); } } placeMarbles(5, Marble.new_mar); // liczba kulek na poczatku placeMarbles(3, Marble.fut_mar); // liczba przyszlych kulek score = 0; } // ... Keep all your existing methods unchanged ... public int calcScores() { int markedForDel = 0; for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { if (field[i][j].marble != null) { if (field[i][j].marble.MarbleState == Marble.mark_for_rem) { markedForDel++; } } } } if (markedForDel > 0) { int bon = (int) (4 + Math.pow(markedForDel - 4, 3)); // 6 kulek = 12 pkt, 7 kulek - 31 pkt score += bon; // Gate log writes to stay under the entry limit if (logEntryCount < MAX_LOG_ENTRIES) { logger.info(String.valueOf(score)); logEntryCount++; } else { // Optional: Disable further logging once the limit is hit logger.setLevel(Level.OFF); } System.out.println("your score: " + score); // 1 pkt za kazda kulke } return score; } }
Step 3: Link log.properties to Your Code on Startup
To pass the custom game.max.log.entries property from your config to the JVM, start your app with this command:
java -Djava.util.logging.config.file=log.properties -Dgame.max.log.entries=$(grep game.max.log.entries log.properties | cut -d'=' -f2) Game
This pulls the limit directly from your log.properties file, so you can adjust it later without changing code.
If you're open to switching, Log4j 2 natively supports entry-count-based log limits, so you won't need custom counters in your code.
Step 1: Add Log4j 2 Dependencies (Maven)
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.20.0</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.20.0</version> </dependency>
Step 2: Create log4j2.xml Config
This config limits logs to 2 entries (current + 1 backup):
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN"> <Appenders> <File name="GameLog" fileName="./logs/Marbles_game.log"> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %level %logger - %msg%n"/> <!-- Trigger rollover after 2 entries (use CountBasedTriggeringPolicy for 2.17+) --> <SizeBasedTriggeringPolicy size="1b"/> <DefaultRolloverStrategy max="1"/> </File> </Appenders> <Loggers> <Root level="INFO"> <AppenderRef ref="GameLog"/> <!-- Disable console logging --> <AppenderRef ref="Console" level="OFF"/> </Root> </Loggers> </Configuration>
Step 3: Update Game Class to Use Log4j
Replace the JUL imports and logger setup:
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; public class Game { // ... All your existing properties ... private static final Logger logger = LogManager.getLogger(Game.class); // ... Keep all methods unchanged, except remove the log counter logic ... public int calcScores() { // ... Existing logic ... if (markedForDel > 0) { int bon = (int) (4 + Math.pow(markedForDel - 4, 3)); score += bon; // Just log normally—Log4j handles the limit logger.info(String.valueOf(score)); System.out.println("your score: " + score); } return score; } }
- Stick with JUL if you want to avoid adding dependencies and don't mind the custom counter code.
- Switch to Log4j 2 if you want cleaner, more flexible logging that scales with your project.
内容的提问来源于stack exchange,提问作者Viola

