Skip to content

Commit d37aebd

Browse files
authored
Support harvester log in subdirectory (geonetwork#9087)
* Support harvester log in subdirectory * Add tests * Fix test * Fallback to base file name * Fix unnessary change
1 parent ce92838 commit d37aebd

File tree

3 files changed

+88
-1
lines changed

3 files changed

+88
-1
lines changed

core/src/main/java/org/fao/geonet/util/LogUtil.java

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,22 @@
2424
package org.fao.geonet.util;
2525

2626
import org.apache.commons.lang.StringUtils;
27+
import org.apache.logging.log4j.LogManager;
2728
import org.apache.logging.log4j.ThreadContext;
29+
import org.apache.logging.log4j.core.appender.routing.RoutingAppender;
30+
import org.apache.logging.log4j.core.config.Configuration;
31+
import org.apache.logging.log4j.core.LoggerContext;
32+
import org.apache.logging.log4j.core.config.Node;
2833
import org.fao.geonet.ApplicationContextHolder;
2934
import org.fao.geonet.kernel.setting.SettingManager;
3035
import org.fao.geonet.kernel.setting.Settings;
36+
import org.fao.geonet.utils.Log;
3137

38+
import java.nio.file.Paths;
3239
import java.text.SimpleDateFormat;
3340
import java.util.Date;
3441
import java.util.TimeZone;
42+
import java.nio.file.Path;
3543

3644
public class LogUtil {
3745

@@ -74,6 +82,46 @@ public static String initializeHarvesterLog(String type, String name) {
7482
ThreadContext.put("logfile", logfile);
7583
ThreadContext.put("timeZone", timeZoneSetting);
7684

77-
return logfile;
85+
try {
86+
return getHarvesterLogfilePath();
87+
} catch (Exception e) {
88+
Log.error("Error retrieving harvester logfile path. Defaulting to base file name.", e);
89+
return logfile;
90+
}
91+
}
92+
93+
/**
94+
* Retrieves the path to the current harvester logfile based on Log4J configuration.
95+
*
96+
* @return the path to the harvester logfile
97+
*/
98+
public static String getHarvesterLogfilePath() {
99+
// Get the top-level log directory
100+
Path logDir = Paths.get(Log.getLogfile().getParent());
101+
102+
// Access Log4J configuration
103+
LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
104+
Configuration config = ctx.getConfiguration();
105+
106+
// Get the Routing appender
107+
RoutingAppender routing = config.getAppender("Harvester");
108+
if (routing == null) {
109+
throw new IllegalStateException("Routing appender 'Harvester' not found");
110+
}
111+
112+
// Find the first <File> node
113+
Node fileNode = routing.getRoutes().getRoutes()[0]
114+
.getNode()
115+
.getChildren()
116+
.stream()
117+
.filter(n -> "File".equalsIgnoreCase(n.getName()))
118+
.findFirst()
119+
.orElseThrow(() -> new IllegalStateException("No <File> node found in Harvester routes"));
120+
121+
// Resolve the full path using the StrSubstitutor
122+
Path fullPath = Paths.get(config.getStrSubstitutor().replace(fileNode.getAttributes().get("fileName")));
123+
124+
// Return the path relative to the log directory
125+
return logDir.relativize(fullPath).toString();
78126
}
79127
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package org.fao.geonet.util;
2+
3+
import org.apache.logging.log4j.ThreadContext;
4+
import org.fao.geonet.utils.Log;
5+
import org.junit.Test;
6+
import org.mockito.MockedStatic;
7+
8+
import java.nio.file.Paths;
9+
10+
import static org.junit.Assert.assertEquals;
11+
import static org.mockito.Mockito.*;
12+
13+
public class LogUtilTest {
14+
15+
@Test
16+
public void retrievesHarvesterLogfilePath() {
17+
ThreadContext.put("logfile", "harvester_geonetwork40_TestHarvester_20251030083002.log");
18+
try (MockedStatic<Log> logMock = mockStatic(Log.class)) {
19+
logMock.when(Log::getLogfile).thenReturn(Paths.get("logs/mock.log").toFile());
20+
21+
assertEquals("harvester_geonetwork40_TestHarvester_20251030083002.log", LogUtil.getHarvesterLogfilePath());
22+
}
23+
}
24+
}

domain/src/test/resources/log4j2.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,24 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Configuration status="warn" dest="out">
3+
<Properties>
4+
<Property name="logs_dir">logs</Property>
5+
</Properties>
36
<Appenders>
47
<Console name="Console" target="SYSTEM_OUT">
58
<PatternLayout pattern="%date{HH:mm:ss.SSS} %-6level [%logger{2}] - %msg%n"/>
69
</Console>
10+
<Routing name="Harvester">
11+
<Routes pattern="$${ctx:logfile}">
12+
<!-- value dynamically determines the name of the log file. -->
13+
<Route>
14+
<File name="harvester-${ctx:harvester}" fileName="${sys:log_dir:-${logs_dir}}/${ctx:logfile:-harvester_default.log}">
15+
<PatternLayout>
16+
<pattern>%date{ISO8601}{${ctx:timeZone}} %-5level [%logger] - %message%n</pattern>
17+
</PatternLayout>
18+
</File>
19+
</Route>
20+
</Routes>
21+
</Routing>
722
</Appenders>
823
<Loggers>
924
<Logger name="org.springframework.aop.framework.CglibAopProxy" level="error"/>

0 commit comments

Comments
 (0)