Skip to content

Commit 344cdd5

Browse files
Copilotptthanh02
andcommitted
Complete logging system implementation with documentation and admin action logging
Co-authored-by: ptthanh02 <73684260+ptthanh02@users.noreply.github.com>
1 parent 6c9c4d1 commit 344cdd5

2 files changed

Lines changed: 242 additions & 0 deletions

File tree

LOGGING.md

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
# SmartSpawner Logging System
2+
3+
## Overview
4+
5+
The SmartSpawner logging system provides comprehensive audit trails for all spawner-related actions. It's designed to be lightweight, asynchronous, and configurable to meet various server administration needs.
6+
7+
## Features
8+
9+
- **Asynchronous Logging**: Non-blocking logging that doesn't impact server performance
10+
- **Multiple Formats**: Support for both human-readable and JSON structured logs
11+
- **Automatic Rotation**: Configurable log file rotation based on size
12+
- **Event Filtering**: Choose which events to log
13+
- **Flexible Storage**: File-based logging with configurable retention
14+
15+
## Configuration
16+
17+
The logging system is configured in `config.yml` under the `logging` section:
18+
19+
```yaml
20+
logging:
21+
# Enable/disable the logging system
22+
enabled: false
23+
24+
# Use asynchronous logging (recommended: true)
25+
async: true
26+
27+
# Output format: false for human-readable, true for JSON
28+
json_format: false
29+
30+
# Also output logs to console
31+
console_output: false
32+
33+
# Directory for log files (relative to plugin folder)
34+
log_directory: "logs/spawner"
35+
36+
# Maximum number of log files to keep
37+
max_log_files: 10
38+
39+
# Maximum log file size in MB before rotation
40+
max_log_size_mb: 10
41+
42+
# Log all events (overrides logged_events list)
43+
log_all_events: false
44+
45+
# Specific events to log
46+
logged_events:
47+
- SPAWNER_PLACE
48+
- SPAWNER_BREAK
49+
- SPAWNER_STACK_HAND
50+
- SPAWNER_STACK_GUI
51+
- SPAWNER_DESTACK_GUI
52+
- SPAWNER_EXP_CLAIM
53+
- SPAWNER_SELL_ALL
54+
- COMMAND_EXECUTE_PLAYER
55+
- COMMAND_EXECUTE_CONSOLE
56+
```
57+
58+
## Available Event Types
59+
60+
### Spawner Lifecycle
61+
- `SPAWNER_PLACE` - When a spawner is placed
62+
- `SPAWNER_BREAK` - When a spawner is broken
63+
- `SPAWNER_EXPLODE` - When a spawner is destroyed by explosion
64+
65+
### Spawner Stacking
66+
- `SPAWNER_STACK_HAND` - Spawner stacked by hand
67+
- `SPAWNER_STACK_GUI` - Spawner stacked via GUI
68+
- `SPAWNER_DESTACK_GUI` - Spawner destacked via GUI
69+
70+
### GUI Interactions
71+
- `SPAWNER_GUI_OPEN` - Main spawner GUI opened
72+
- `SPAWNER_STORAGE_OPEN` - Storage GUI opened
73+
- `SPAWNER_STACKER_OPEN` - Stacker GUI opened
74+
75+
### Player Actions
76+
- `SPAWNER_EXP_CLAIM` - Experience claimed from spawner
77+
- `SPAWNER_SELL_ALL` - Items sold from spawner
78+
- `SPAWNER_SELL_AND_CLAIM` - Items sold and experience claimed
79+
80+
### Commands
81+
- `COMMAND_EXECUTE_PLAYER` - Command executed by player
82+
- `COMMAND_EXECUTE_CONSOLE` - Command executed by console
83+
- `COMMAND_EXECUTE_RCON` - Command executed by RCON
84+
85+
### Other Events
86+
- `SPAWNER_EGG_CHANGE` - Entity type changed
87+
- `LOOT_GENERATED` - Loot generation event
88+
- `HOPPER_COLLECT` - Hopper collection
89+
- `ADMIN_GIVE` - Admin gave spawner to player
90+
- `ADMIN_REMOVE` - Admin removed spawner
91+
- `CONFIG_RELOAD` - Configuration reloaded
92+
93+
## Log Formats
94+
95+
### Human-Readable Format
96+
```
97+
[2025-10-12 18:30:45] Spawner placed | Player: Steve | Location: world (100, 64, 200) | Entity: ZOMBIE | quantity=1
98+
[2025-10-12 18:31:20] Storage GUI opened | Player: Steve | Location: world (100, 64, 200) | Entity: ZOMBIE | page=1 total_pages=1
99+
```
100+
101+
### JSON Format
102+
```json
103+
{"timestamp":"2025-10-12 18:30:45","timestamp_ms":1697134245000,"event_type":"SPAWNER_PLACE","description":"Spawner placed","player":"Steve","player_uuid":"069a79f4-44e9-4726-a5be-fca90e38aaf5","location":{"world":"world","x":100,"y":64,"z":200},"entity_type":"ZOMBIE","metadata":{"quantity":1}}
104+
{"timestamp":"2025-10-12 18:31:20","timestamp_ms":1697134280000,"event_type":"SPAWNER_STORAGE_OPEN","description":"Storage GUI opened","player":"Steve","player_uuid":"069a79f4-44e9-4726-a5be-fca90e38aaf5","location":{"world":"world","x":100,"y":64,"z":200},"entity_type":"ZOMBIE","metadata":{"page":1,"total_pages":1}}
105+
```
106+
107+
## Log File Management
108+
109+
### Location
110+
Log files are stored in `plugins/SmartSpawner/logs/spawner/` by default (configurable).
111+
112+
### File Naming
113+
- Human-readable: `spawner-YYYY-MM-DD.log`
114+
- JSON format: `spawner-YYYY-MM-DD.json`
115+
- Rotated files: `spawner-YYYY-MM-DD_HH-mm-ss.log` or `.json`
116+
117+
### Rotation
118+
Logs are automatically rotated when they exceed the configured size (`max_log_size_mb`). Oldest files are deleted when the number of files exceeds `max_log_files`.
119+
120+
## Programmatic Usage
121+
122+
### Direct Logging
123+
```java
124+
SmartSpawner plugin = SmartSpawner.getInstance();
125+
SpawnerActionLogger logger = plugin.getSpawnerActionLogger();
126+
127+
// Simple logging
128+
logger.log(SpawnerEventType.LOOT_GENERATED, builder ->
129+
builder.location(location)
130+
.entityType(EntityType.ZOMBIE)
131+
.metadata("items_generated", 10)
132+
);
133+
134+
// Player action logging
135+
logger.log(SpawnerEventType.SPAWNER_GUI_OPEN, builder ->
136+
builder.player(player.getName(), player.getUniqueId())
137+
.location(spawner.getSpawnerLocation())
138+
.entityType(spawner.getEntityType())
139+
);
140+
```
141+
142+
### Custom Event Logging
143+
The logging system automatically logs all spawner-related events through the `SpawnerAuditListener`. For custom logging:
144+
145+
```java
146+
SpawnerLogEntry entry = new SpawnerLogEntry.Builder(SpawnerEventType.CUSTOM_EVENT)
147+
.player(playerName, playerUuid)
148+
.location(location)
149+
.entityType(entityType)
150+
.metadata("custom_key", "custom_value")
151+
.build();
152+
153+
logger.log(entry);
154+
```
155+
156+
## Performance Considerations
157+
158+
1. **Async Logging**: Always use `async: true` in production to prevent blocking the main thread
159+
2. **Event Filtering**: Only log necessary events to reduce I/O operations
160+
3. **File Rotation**: Configure appropriate `max_log_size_mb` based on your server activity
161+
4. **Console Output**: Disable `console_output` in production unless debugging
162+
163+
## Troubleshooting
164+
165+
### Logs Not Being Created
166+
1. Check that `enabled: true` in config.yml
167+
2. Verify plugin has write permissions to the log directory
168+
3. Ensure at least one event type is in the `logged_events` list
169+
170+
### Performance Issues
171+
1. Disable `console_output` if enabled
172+
2. Reduce the number of logged events
173+
3. Increase `max_log_size_mb` to reduce rotation frequency
174+
4. Verify `async: true` is set
175+
176+
### Missing Events
177+
1. Check that the event type is included in `logged_events`
178+
2. Verify `log_all_events` is false if using selective logging
179+
3. Ensure the event is not being cancelled by another plugin
180+
181+
## Best Practices
182+
183+
1. **Production Setup**:
184+
- Enable only critical events (place, break, admin actions)
185+
- Use JSON format for easier parsing
186+
- Set reasonable rotation limits (10-20 files, 10-20 MB each)
187+
- Keep `async: true`
188+
189+
2. **Debugging Setup**:
190+
- Enable all events with `log_all_events: true`
191+
- Use human-readable format
192+
- Enable `console_output: true`
193+
- Lower file size limits for more frequent rotation
194+
195+
3. **Archive Old Logs**:
196+
- Periodically backup and remove old log files
197+
- Consider external log aggregation tools for long-term storage
198+
- Use log analysis tools for JSON formatted logs
199+
200+
## Integration with External Tools
201+
202+
### Log Aggregation
203+
JSON formatted logs can be easily imported into:
204+
- Elasticsearch + Kibana
205+
- Splunk
206+
- Graylog
207+
- Logstash
208+
209+
### Analysis Tools
210+
- `jq` for command-line JSON parsing
211+
- Python scripts for custom analysis
212+
- Grafana for visualization
213+
214+
Example `jq` query to find all spawner placements by a specific player:
215+
```bash
216+
cat spawner-2025-10-12.json | jq 'select(.event_type == "SPAWNER_PLACE" and .player == "Steve")'
217+
```
218+
219+
## Future Enhancements
220+
221+
Potential future additions:
222+
- Database backend support (MySQL, MongoDB)
223+
- Remote logging to external services
224+
- Web dashboard for log visualization
225+
- Real-time alerting for suspicious activities
226+
- Export to CSV/Excel formats

core/src/main/java/github/nighter/smartspawner/commands/give/GiveSubCommand.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,22 @@ private int executeGive(CommandContext<CommandSourceStack> context, boolean isVa
164164
String messageKey = "command_give_spawner_";
165165
plugin.getMessageService().sendMessage(sender, messageKey + "given", senderPlaceholders);
166166
plugin.getMessageService().sendMessage(target, messageKey + "received", targetPlaceholders);
167+
168+
// Log admin give action
169+
if (plugin.getSpawnerActionLogger() != null) {
170+
plugin.getSpawnerActionLogger().log(github.nighter.smartspawner.logging.SpawnerEventType.ADMIN_GIVE, builder -> {
171+
if (sender instanceof Player senderPlayer) {
172+
builder.player(senderPlayer.getName(), senderPlayer.getUniqueId());
173+
} else {
174+
builder.metadata("sender", sender.getName());
175+
}
176+
builder.entityType(entityType)
177+
.metadata("target_player", target.getName())
178+
.metadata("target_uuid", target.getUniqueId().toString())
179+
.metadata("amount", amount)
180+
.metadata("vanilla", vanilla);
181+
});
182+
}
167183

168184
return 1;
169185
} catch (Exception e) {

0 commit comments

Comments
 (0)