Skip to content

Commit 8551ac1

Browse files
committed
feat: supports writing agent log to specified path
1 parent 84fed02 commit 8551ac1

File tree

10 files changed

+201
-20
lines changed

10 files changed

+201
-20
lines changed

arex-agent-bootstrap/src/main/java/io/arex/agent/bootstrap/AgentInitializer.java

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,22 @@
22

33
import io.arex.agent.bootstrap.constants.ConfigConstants;
44
import io.arex.agent.bootstrap.util.AdviceClassesCollector;
5+
import io.arex.agent.bootstrap.util.StringUtil;
56
import java.io.File;
7+
import java.io.IOException;
68
import java.lang.instrument.Instrumentation;
79
import java.lang.reflect.Constructor;
10+
import java.nio.file.Files;
11+
import java.nio.file.Path;
12+
import java.nio.file.Paths;
13+
import java.time.LocalDate;
14+
import java.time.LocalDateTime;
15+
import java.time.format.DateTimeFormatter;
816

917
public class AgentInitializer {
1018

19+
public static final String SIMPLE_DATE_FORMAT_MILLIS = "yyyy-MM-dd HH:mm:ss.SSS";
20+
1121
private static ClassLoader classLoader;
1222

1323
/**
@@ -18,8 +28,7 @@ public static void initialize(Instrumentation inst, File agentFile, String agent
1828
if (classLoader != null) {
1929
return;
2030
}
21-
System.setProperty(ConfigConstants.SHADED_LOGGER_SHOW_DATE_TIME, "true");
22-
System.setProperty(ConfigConstants.SHADED_LOGGER_DATE_TIME_FORMAT, "yyyy-MM-dd HH:mm:ss:SSS");
31+
initializeSimpleLoggerConfig(agentFile.getParent());
2332
File[] extensionFiles = getExtensionJarFiles(agentFile);
2433
classLoader = new AgentClassLoader(agentFile, parentClassLoader, extensionFiles);
2534
InstrumentationHolder.setAgentClassLoader(classLoader);
@@ -56,4 +65,28 @@ private static AgentInstaller createAgentInstaller(Instrumentation inst, File fi
5665
Constructor<?> constructor = clazz.getDeclaredConstructor(Instrumentation.class, File.class, String.class);
5766
return (AgentInstaller) constructor.newInstance(inst, file, agentArgs);
5867
}
68+
69+
private static void initializeSimpleLoggerConfig(String agentFileParent) {
70+
System.setProperty(ConfigConstants.SIMPLE_LOGGER_SHOW_DATE_TIME, Boolean.TRUE.toString());
71+
System.setProperty(ConfigConstants.SIMPLE_LOGGER_DATE_TIME_FORMAT, SIMPLE_DATE_FORMAT_MILLIS);
72+
73+
String logPath = System.getProperty(ConfigConstants.LOG_PATH);
74+
if (StringUtil.isEmpty(logPath)) {
75+
logPath = agentFileParent + "/logs";
76+
System.setProperty(ConfigConstants.LOG_PATH, logPath);
77+
}
78+
79+
Path filePath = Paths.get(logPath);
80+
if (Files.notExists(filePath)) {
81+
try {
82+
Files.createDirectories(filePath);
83+
} catch (IOException e) {
84+
System.err.printf("%s [AREX] Failed to create log directory: %s%n",
85+
LocalDateTime.now().format(DateTimeFormatter.ofPattern(SIMPLE_DATE_FORMAT_MILLIS)), logPath);
86+
return;
87+
}
88+
}
89+
String logFilePath = logPath + "/arex." + LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE) + ".log";
90+
System.setProperty(ConfigConstants.SIMPLE_LOGGER_FILE, logFilePath);
91+
}
5992
}

arex-agent-bootstrap/src/main/java/io/arex/agent/bootstrap/constants/ConfigConstants.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,11 @@ private ConfigConstants() {
3030
public static final String DECELERATE_CODE = "arex.decelerate.code";
3131
public static final String SERIALIZER_CONFIG = "arex.serializer.config";
3232
public static final String BUFFER_SIZE = "arex.buffer.size";
33-
public static final String SHADED_LOGGER_SHOW_DATE_TIME = "shaded.org.slf4j.simpleLogger.showDateTime";
34-
public static final String SHADED_LOGGER_DATE_TIME_FORMAT = "shaded.org.slf4j.simpleLogger.dateTimeFormat";
33+
public static final String SIMPLE_LOGGER_SHOW_DATE_TIME = "shaded.org.slf4j.simpleLogger.showDateTime";
34+
public static final String SIMPLE_LOGGER_DATE_TIME_FORMAT = "shaded.org.slf4j.simpleLogger.dateTimeFormat";
35+
public static final String SIMPLE_LOGGER_FILE = "shaded.org.slf4j.simpleLogger.logFile";
3536
public static final String COVERAGE_PACKAGES = "arex.coverage.packages";
3637
public static final String APP_CLASSLOADER_NAME = "jdk.internal.loader.ClassLoaders$AppClassLoader";
3738
public static final String API_TOKEN = "arex.api.token";
39+
public static final String LOG_PATH = "arex.log.path";
3840
}

arex-agent-core/src/main/java/io/arex/agent/instrumentation/BaseAgentInstaller.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
import io.arex.agent.bootstrap.util.FileUtils;
77
import io.arex.foundation.config.ConfigManager;
88
import io.arex.foundation.healthy.HealthManager;
9+
import io.arex.foundation.logger.AgentLoggerFactory;
10+
import io.arex.foundation.logger.AgentLogger;
11+
import io.arex.foundation.serializer.jackson.JacksonSerializer;
912
import io.arex.foundation.services.ConfigService;
1013
import io.arex.foundation.services.DataCollectorService;
1114
import io.arex.foundation.services.TimerService;
@@ -23,11 +26,9 @@
2326
import java.lang.instrument.Instrumentation;
2427

2528
import net.bytebuddy.dynamic.scaffold.TypeWriter;
26-
import org.slf4j.Logger;
27-
import org.slf4j.LoggerFactory;
2829

2930
public abstract class BaseAgentInstaller implements AgentInstaller {
30-
private static final Logger LOGGER = LoggerFactory.getLogger(BaseAgentInstaller.class);
31+
private static final AgentLogger LOGGER = AgentLoggerFactory.getAgentLogger(BaseAgentInstaller.class);
3132
private static final String BYTECODE_DUMP_DIR = "/bytecode-dump";
3233
protected final Instrumentation instrumentation;
3334
protected final File agentFile;

arex-agent-core/src/main/java/io/arex/agent/instrumentation/InstrumentationInstaller.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package io.arex.agent.instrumentation;
22

3+
import io.arex.foundation.logger.AgentLoggerFactory;
4+
import io.arex.foundation.logger.AgentLogger;
35
import io.arex.inst.extension.ExtensionTransformer;
46
import io.arex.inst.extension.ModuleInstrumentation;
57
import io.arex.inst.extension.MethodInstrumentation;
@@ -23,16 +25,14 @@
2325
import net.bytebuddy.dynamic.loading.ClassReloadingStrategy;
2426
import net.bytebuddy.dynamic.scaffold.MethodGraph;
2527
import net.bytebuddy.matcher.ElementMatcher;
26-
import org.slf4j.Logger;
27-
import org.slf4j.LoggerFactory;
2828

2929
import java.io.File;
3030
import java.lang.instrument.Instrumentation;
3131
import java.util.*;
3232

3333
@SuppressWarnings("unused")
3434
public class InstrumentationInstaller extends BaseAgentInstaller {
35-
private static final Logger LOGGER = LoggerFactory.getLogger(InstrumentationInstaller.class);
35+
private static final AgentLogger LOGGER = AgentLoggerFactory.getAgentLogger(InstrumentationInstaller.class);
3636
private ModuleInstrumentation dynamicModule;
3737
private ResettableClassFileTransformer resettableClassFileTransformer;
3838

arex-agent-core/src/main/java/io/arex/agent/instrumentation/TransformListener.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
package io.arex.agent.instrumentation;
22

33
import io.arex.foundation.config.ConfigManager;
4+
import io.arex.foundation.logger.AgentLogger;
5+
import io.arex.foundation.logger.AgentLoggerFactory;
46
import net.bytebuddy.agent.builder.AgentBuilder;
57
import net.bytebuddy.description.type.TypeDescription;
68
import net.bytebuddy.dynamic.DynamicType;
79
import net.bytebuddy.utility.JavaModule;
8-
import org.slf4j.Logger;
9-
import org.slf4j.LoggerFactory;
1010

1111
public class TransformListener extends AgentBuilder.Listener.Adapter {
12-
private static final Logger LOGGER = LoggerFactory.getLogger(TransformListener.class);
12+
private static final AgentLogger LOGGER = AgentLoggerFactory.getAgentLogger(TransformListener.class);
1313

1414
@Override
1515
public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module,

arex-instrumentation-foundation/src/main/java/io/arex/foundation/config/ConfigManager.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import io.arex.agent.bootstrap.util.ArrayUtils;
55
import io.arex.agent.bootstrap.util.MapUtils;
66
import io.arex.agent.bootstrap.util.StringUtil;
7+
import io.arex.foundation.logger.AgentLogger;
8+
import io.arex.foundation.logger.AgentLoggerFactory;
79
import io.arex.foundation.model.ConfigQueryResponse.DynamicClassConfiguration;
810
import io.arex.foundation.model.ConfigQueryResponse.ResponseBody;
911
import io.arex.foundation.model.ConfigQueryResponse.ServiceCollectConfig;
@@ -16,8 +18,6 @@
1618
import io.arex.agent.bootstrap.util.ServiceLoader;
1719
import java.util.concurrent.atomic.AtomicBoolean;
1820
import java.util.stream.Collectors;
19-
import org.slf4j.Logger;
20-
import org.slf4j.LoggerFactory;
2121

2222
import java.io.IOException;
2323
import java.nio.file.Files;
@@ -34,7 +34,7 @@
3434

3535
public class ConfigManager {
3636

37-
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigManager.class);
37+
private static final AgentLogger LOGGER = AgentLoggerFactory.getAgentLogger(ConfigManager.class);
3838
public static final ConfigManager INSTANCE = new ConfigManager();
3939
public static final AtomicBoolean FIRST_TRANSFORM = new AtomicBoolean(false);
4040
private static final int DEFAULT_RECORDING_RATE = 1;
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package io.arex.foundation.logger;
2+
3+
import java.io.PrintStream;
4+
import java.time.LocalDateTime;
5+
import java.time.format.DateTimeFormatter;
6+
import org.slf4j.helpers.FormattingTuple;
7+
import org.slf4j.helpers.MessageFormatter;
8+
9+
/**
10+
* @since 2024/4/22
11+
*/
12+
public class AgentLogger {
13+
private final String name;
14+
private final PrintStream printStream;
15+
public AgentLogger(String name, PrintStream printStream) {
16+
this.name = name;
17+
this.printStream = printStream;
18+
}
19+
20+
public void warn(String format) {
21+
warn(format, null);
22+
}
23+
24+
public void warn(String format, Object arg) {
25+
warn(format, arg, null);
26+
}
27+
28+
public void warn(String format, Object arg1, Object arg2) {
29+
formatAndLog(format, arg1, arg2);
30+
}
31+
32+
public void info(String format, Object... arguments) {
33+
formatAndLog(format, arguments);
34+
}
35+
36+
public void error(String format, Object... arguments) {
37+
formatAndLog(format, arguments);
38+
}
39+
40+
public void error(String msg, Throwable t) {
41+
write(msg, t);
42+
}
43+
44+
private void formatAndLog(String format, Object arg1, Object arg2) {
45+
FormattingTuple tp = MessageFormatter.format(format, arg1, arg2);
46+
write(tp.getMessage(), tp.getThrowable());
47+
}
48+
49+
private void formatAndLog(String format, Object... arguments) {
50+
FormattingTuple tp = MessageFormatter.arrayFormat(format, arguments);
51+
write(tp.getMessage(), tp.getThrowable());
52+
}
53+
54+
private void write(String message, Throwable t) {
55+
StringBuilder builder = new StringBuilder(32);
56+
builder.append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"))).append(" ");
57+
builder.append("[").append(Thread.currentThread().getName()).append("] ").append(" ");
58+
builder.append(name).append(" - ");
59+
builder.append(message);
60+
61+
printStream.println(builder);
62+
writeThrowable(t, printStream);
63+
printStream.flush();
64+
}
65+
66+
private void writeThrowable(Throwable t, PrintStream targetStream) {
67+
if (t != null) {
68+
t.printStackTrace(targetStream);
69+
}
70+
}
71+
72+
public String getName() {
73+
return name;
74+
}
75+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package io.arex.foundation.logger;
2+
3+
import io.arex.agent.bootstrap.constants.ConfigConstants;
4+
import io.arex.agent.bootstrap.util.StringUtil;
5+
import java.io.FileNotFoundException;
6+
import java.io.FileOutputStream;
7+
import java.io.PrintStream;
8+
import java.time.LocalDate;
9+
import java.time.format.DateTimeFormatter;
10+
import java.util.concurrent.ConcurrentHashMap;
11+
import java.util.concurrent.ConcurrentMap;
12+
13+
/**
14+
* @since 2024/4/23
15+
*/
16+
public class AgentLoggerFactory {
17+
static final ConcurrentMap<String, AgentLogger> loggerMap;
18+
19+
private static final PrintStream agentPrintStream;
20+
21+
static {
22+
loggerMap = new ConcurrentHashMap<>();
23+
agentPrintStream = getPrintStream("startup");
24+
}
25+
26+
public static AgentLogger getAgentLogger(Class<?> clazz) {
27+
return loggerMap.computeIfAbsent(clazz.getName(), name -> createLogger(name, agentPrintStream));
28+
}
29+
30+
private static AgentLogger createLogger(String name, PrintStream printStream) {
31+
return new AgentLogger(name, printStream);
32+
}
33+
34+
private static PrintStream getPrintStream(String fileName) {
35+
try {
36+
String logPath = System.getProperty(ConfigConstants.LOG_PATH);
37+
if (StringUtil.isEmpty(logPath)) {
38+
return System.out;
39+
}
40+
41+
String logFilePath = logPath + "/arex." + fileName + "." + LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE) + ".log";
42+
return new PrintStream(new FileOutputStream(logFilePath, true));
43+
} catch (FileNotFoundException e) {
44+
return System.out;
45+
}
46+
}
47+
48+
}

arex-instrumentation-foundation/src/main/java/io/arex/foundation/services/ConfigService.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import io.arex.agent.bootstrap.constants.ConfigConstants;
55
import io.arex.agent.bootstrap.model.ArexMocker;
66
import io.arex.agent.bootstrap.util.MapUtils;
7+
import io.arex.foundation.logger.AgentLogger;
8+
import io.arex.foundation.logger.AgentLoggerFactory;
79
import io.arex.foundation.model.*;
810
import io.arex.foundation.config.ConfigManager;
911
import io.arex.foundation.util.httpclient.AsyncHttpClientUtil;
@@ -16,9 +18,6 @@
1618
import java.util.Properties;
1719
import java.util.concurrent.atomic.AtomicBoolean;
1820

19-
import org.slf4j.Logger;
20-
import org.slf4j.LoggerFactory;
21-
2221
/**
2322
* ConfigService
2423
* todo: config file, run backend
@@ -27,7 +26,7 @@
2726
*/
2827
public class ConfigService {
2928

30-
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigService.class);
29+
private static final AgentLogger LOGGER = AgentLoggerFactory.getAgentLogger(ConfigService.class);
3130
private static final Map<String, String> TAGS_PROPERTIES = new HashMap<>();
3231

3332
public static final ConfigService INSTANCE = new ConfigService();
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package io.arex.foundation.logger;
2+
3+
import static org.junit.jupiter.api.Assertions.*;
4+
5+
import io.arex.agent.bootstrap.constants.ConfigConstants;
6+
import org.junit.jupiter.api.Test;
7+
8+
/**
9+
* @since 2024/4/23
10+
*/
11+
class AgentLoggerFactoryTest {
12+
13+
@Test
14+
void getAgentLogger() {
15+
System.setProperty(ConfigConstants.LOG_PATH, "var/log");
16+
AgentLogger agentLogger = AgentLoggerFactory.getAgentLogger(AgentLoggerFactoryTest.class);
17+
assertEquals(AgentLoggerFactoryTest.class.getName(), agentLogger.getName());
18+
19+
agentLogger.error("{} message test", "error");
20+
21+
agentLogger.error("{} message test", "error", new RuntimeException("error"));
22+
}
23+
}

0 commit comments

Comments
 (0)