-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
TS/31571 Send log to Teamscale via a custom Appender
#518
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
@@ -1,7 +1,9 @@ | ||||
package com.teamscale.jacoco.agent; | ||||
|
||||
import com.teamscale.client.HttpUtils; | ||||
import com.teamscale.client.TeamscaleServer; | ||||
Check warning on line 4 in agent/src/main/java/com/teamscale/jacoco/agent/PreMain.java cqse.teamscale.io / teamscale-findingsagent/src/main/java/com/teamscale/jacoco/agent/PreMain.java#L4
|
||||
import com.teamscale.jacoco.agent.configuration.AgentOptionReceiveException; | ||||
import com.teamscale.jacoco.agent.logging.LogToTeamscaleAppender; | ||||
import com.teamscale.jacoco.agent.options.AgentOptionParseException; | ||||
import com.teamscale.jacoco.agent.options.AgentOptions; | ||||
import com.teamscale.jacoco.agent.options.AgentOptionsParser; | ||||
|
@@ -11,10 +13,11 @@ | |||
import com.teamscale.jacoco.agent.options.TeamscalePropertiesUtils; | ||||
import com.teamscale.jacoco.agent.testimpact.TestwiseCoverageAgent; | ||||
import com.teamscale.jacoco.agent.upload.UploaderException; | ||||
import com.teamscale.jacoco.agent.upload.teamscale.TeamscaleConfig; | ||||
Check warning on line 16 in agent/src/main/java/com/teamscale/jacoco/agent/PreMain.java cqse.teamscale.io / teamscale-findingsagent/src/main/java/com/teamscale/jacoco/agent/PreMain.java#L16
|
||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove unused import. The import - import com.teamscale.jacoco.agent.upload.teamscale.TeamscaleConfig; Committable suggestion
Suggested change
ToolsGitHub Check: teamscale-findings
|
||||
import com.teamscale.jacoco.agent.util.AgentUtils; | ||||
import com.teamscale.jacoco.agent.util.DebugLogDirectoryPropertyDefiner; | ||||
import com.teamscale.jacoco.agent.util.LogDirectoryPropertyDefiner; | ||||
import com.teamscale.jacoco.agent.util.LoggingUtils; | ||||
import com.teamscale.jacoco.agent.logging.DebugLogDirectoryPropertyDefiner; | ||||
import com.teamscale.jacoco.agent.logging.LogDirectoryPropertyDefiner; | ||||
import com.teamscale.jacoco.agent.logging.LoggingUtils; | ||||
import org.conqat.lib.commons.collections.CollectionUtils; | ||||
import org.conqat.lib.commons.filesystem.FileSystemUtils; | ||||
import org.conqat.lib.commons.string.StringUtils; | ||||
|
@@ -31,6 +34,8 @@ | |||
import java.util.List; | ||||
import java.util.Optional; | ||||
|
||||
import static com.teamscale.jacoco.agent.logging.LoggingUtils.getLoggerContext; | ||||
|
||||
/** Container class for the premain entry point for the agent. */ | ||||
public class PreMain { | ||||
|
||||
|
@@ -149,6 +154,10 @@ | |||
loggingResources = LoggingUtils.initializeLogging(agentOptions.getLoggingConfig()); | ||||
logger.info("Logging to " + new LogDirectoryPropertyDefiner().getPropertyValue()); | ||||
} | ||||
|
||||
if (agentOptions.getTeamscaleServerOptions().isConfiguredForServerConnection()) { | ||||
LogToTeamscaleAppender.addTeamscaleAppenderTo(getLoggerContext(), agentOptions); | ||||
} | ||||
} | ||||
|
||||
/** Closes the opened logging contexts. */ | ||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
package com.teamscale.jacoco.agent.util; | ||
package com.teamscale.jacoco.agent.logging; | ||
|
||
import java.nio.file.Path; | ||
|
||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,126 @@ | ||||||||||||||||||||||||||||||||||||||||||||||
package com.teamscale.jacoco.agent.logging; | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
import ch.qos.logback.classic.Logger; | ||||||||||||||||||||||||||||||||||||||||||||||
import ch.qos.logback.classic.LoggerContext; | ||||||||||||||||||||||||||||||||||||||||||||||
import ch.qos.logback.classic.spi.ILoggingEvent; | ||||||||||||||||||||||||||||||||||||||||||||||
import ch.qos.logback.core.AppenderBase; | ||||||||||||||||||||||||||||||||||||||||||||||
import com.teamscale.client.ProfilerLogEntry; | ||||||||||||||||||||||||||||||||||||||||||||||
import com.teamscale.client.TeamscaleClient; | ||||||||||||||||||||||||||||||||||||||||||||||
import com.teamscale.jacoco.agent.options.AgentOptions; | ||||||||||||||||||||||||||||||||||||||||||||||
import retrofit2.Call; | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
import java.time.Duration; | ||||||||||||||||||||||||||||||||||||||||||||||
import java.util.ArrayList; | ||||||||||||||||||||||||||||||||||||||||||||||
import java.util.List; | ||||||||||||||||||||||||||||||||||||||||||||||
import java.util.concurrent.*; | ||||||||||||||||||||||||||||||||||||||||||||||
Check warning on line 15 in agent/src/main/java/com/teamscale/jacoco/agent/logging/LogToTeamscaleAppender.java cqse.teamscale.io / teamscale-findingsagent/src/main/java/com/teamscale/jacoco/agent/logging/LogToTeamscaleAppender.java#L15
|
||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid star imports. Star import of - import java.util.concurrent.*;
+ import java.util.concurrent.Executors;
+ import java.util.concurrent.ScheduledExecutorService;
+ import java.util.concurrent.TimeUnit;
+ import java.util.concurrent.CompletableFuture; Committable suggestion
Suggested change
ToolsGitHub Check: teamscale-findings
|
||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
public class LogToTeamscaleAppender extends AppenderBase<ILoggingEvent> { | ||||||||||||||||||||||||||||||||||||||||||||||
Check warning on line 17 in agent/src/main/java/com/teamscale/jacoco/agent/logging/LogToTeamscaleAppender.java cqse.teamscale.io / teamscale-findingsagent/src/main/java/com/teamscale/jacoco/agent/logging/LogToTeamscaleAppender.java#L17
|
||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add class-level Javadoc. The class /**
* Custom appender that sends logs to Teamscale.
*/
public class LogToTeamscaleAppender extends AppenderBase<ILoggingEvent> { ToolsGitHub Check: teamscale-findings
|
||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
private String profilerId; | ||||||||||||||||||||||||||||||||||||||||||||||
private TeamscaleClient teamscaleClient; | ||||||||||||||||||||||||||||||||||||||||||||||
private int batchSize = 10; | ||||||||||||||||||||||||||||||||||||||||||||||
private Duration flushInterval = Duration.ofSeconds(3); | ||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is |
||||||||||||||||||||||||||||||||||||||||||||||
private final List<ProfilerLogEntry> logBuffer = new ArrayList<>(); | ||||||||||||||||||||||||||||||||||||||||||||||
private final ScheduledExecutorService scheduler; | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
public LogToTeamscaleAppender() { | ||||||||||||||||||||||||||||||||||||||||||||||
this.scheduler = Executors.newScheduledThreadPool(1, r -> { | ||||||||||||||||||||||||||||||||||||||||||||||
// Make the thread a daemon so that it does not prevent the JVM from terminating. | ||||||||||||||||||||||||||||||||||||||||||||||
Thread t = Executors.defaultThreadFactory().newThread(r); | ||||||||||||||||||||||||||||||||||||||||||||||
t.setDaemon(true); | ||||||||||||||||||||||||||||||||||||||||||||||
return t; | ||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
public void setTeamscaleClient(TeamscaleClient teamscaleClient) { | ||||||||||||||||||||||||||||||||||||||||||||||
this.teamscaleClient = teamscaleClient; | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
public void setProfilerId(String profilerId) { | ||||||||||||||||||||||||||||||||||||||||||||||
this.profilerId = profilerId; | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
public void setBatchSize(int batchSize) { | ||||||||||||||||||||||||||||||||||||||||||||||
this.batchSize = batchSize; | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
public void setFlushInterval(Duration flushInterval) { | ||||||||||||||||||||||||||||||||||||||||||||||
this.flushInterval = flushInterval; | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
@Override | ||||||||||||||||||||||||||||||||||||||||||||||
public void start() { | ||||||||||||||||||||||||||||||||||||||||||||||
super.start(); | ||||||||||||||||||||||||||||||||||||||||||||||
scheduler.scheduleAtFixedRate(this::flush, flushInterval.toMillis(), flushInterval.toMillis(), TimeUnit.MILLISECONDS); | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
@Override | ||||||||||||||||||||||||||||||||||||||||||||||
protected void append(ILoggingEvent eventObject) { | ||||||||||||||||||||||||||||||||||||||||||||||
synchronized (logBuffer) { | ||||||||||||||||||||||||||||||||||||||||||||||
logBuffer.add(formatLog(eventObject)); | ||||||||||||||||||||||||||||||||||||||||||||||
if (logBuffer.size() >= batchSize) { | ||||||||||||||||||||||||||||||||||||||||||||||
flush(); | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
private ProfilerLogEntry formatLog(ILoggingEvent eventObject) { | ||||||||||||||||||||||||||||||||||||||||||||||
long timestamp = eventObject.getTimeStamp(); | ||||||||||||||||||||||||||||||||||||||||||||||
String message = eventObject.getFormattedMessage(); | ||||||||||||||||||||||||||||||||||||||||||||||
String severity = eventObject.getLevel().toString(); | ||||||||||||||||||||||||||||||||||||||||||||||
return new ProfilerLogEntry(timestamp, message, severity); | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
private void flush() { | ||||||||||||||||||||||||||||||||||||||||||||||
List<ProfilerLogEntry> logsToSend; | ||||||||||||||||||||||||||||||||||||||||||||||
synchronized (logBuffer) { | ||||||||||||||||||||||||||||||||||||||||||||||
if (logBuffer.isEmpty()) { | ||||||||||||||||||||||||||||||||||||||||||||||
return; | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
logsToSend = new ArrayList<>(logBuffer); | ||||||||||||||||||||||||||||||||||||||||||||||
logBuffer.clear(); | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
sendLogs(logsToSend); | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
private void sendLogs(List<ProfilerLogEntry> logs) { | ||||||||||||||||||||||||||||||||||||||||||||||
CompletableFuture.runAsync(() -> { | ||||||||||||||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||||||||||||||
Call<Void> call = teamscaleClient.service.postProfilerLog(profilerId, logs); | ||||||||||||||||||||||||||||||||||||||||||||||
retrofit2.Response<Void> response = call.execute(); | ||||||||||||||||||||||||||||||||||||||||||||||
if (!response.isSuccessful()) { | ||||||||||||||||||||||||||||||||||||||||||||||
throw new RuntimeException("Failed to send log: HTTP error code : " + response.code()); | ||||||||||||||||||||||||||||||||||||||||||||||
Check failure on line 92 in agent/src/main/java/com/teamscale/jacoco/agent/logging/LogToTeamscaleAppender.java cqse.teamscale.io / teamscale-findingsagent/src/main/java/com/teamscale/jacoco/agent/logging/LogToTeamscaleAppender.java#L92
|
||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid throwing generic exceptions. Throwing generic exceptions like - throw new RuntimeException("Failed to send log: HTTP error code : " + response.code());
+ throw new TeamscaleLogException("Failed to send log: HTTP error code : " + response.code()); Add a custom exception class public class TeamscaleLogException extends Exception {
public TeamscaleLogException(String message) {
super(message);
}
} ToolsGitHub Check: teamscale-findings
|
||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
} catch (Exception e) { | ||||||||||||||||||||||||||||||||||||||||||||||
e.printStackTrace(); // Handle exceptions appropriately in production code | ||||||||||||||||||||||||||||||||||||||||||||||
Check warning on line 95 in agent/src/main/java/com/teamscale/jacoco/agent/logging/LogToTeamscaleAppender.java cqse.teamscale.io / teamscale-findingsagent/src/main/java/com/teamscale/jacoco/agent/logging/LogToTeamscaleAppender.java#L95
|
||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
Check failure on line 96 in agent/src/main/java/com/teamscale/jacoco/agent/logging/LogToTeamscaleAppender.java cqse.teamscale.io / teamscale-findingsagent/src/main/java/com/teamscale/jacoco/agent/logging/LogToTeamscaleAppender.java#L94-L96
|
||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+94
to
+96
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid catching generic exceptions. Catching generic exceptions like - } catch (Exception e) {
+ } catch (IOException e) {
ToolsGitHub Check: teamscale-findings
|
||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||
Check warning on line 97 in agent/src/main/java/com/teamscale/jacoco/agent/logging/LogToTeamscaleAppender.java cqse.teamscale.io / teamscale-findingsagent/src/main/java/com/teamscale/jacoco/agent/logging/LogToTeamscaleAppender.java#L87-L97
|
||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+87
to
+97
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid using The - e.printStackTrace(); // Handle exceptions appropriately in production code
+ logger.error("Failed to send logs to Teamscale: " + e.getMessage(), e); Committable suggestion
Suggested change
ToolsGitHub Check: teamscale-findings
|
||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
@Override | ||||||||||||||||||||||||||||||||||||||||||||||
public void stop() { | ||||||||||||||||||||||||||||||||||||||||||||||
scheduler.shutdown(); | ||||||||||||||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||||||||||||||
if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) { | ||||||||||||||||||||||||||||||||||||||||||||||
scheduler.shutdownNow(); | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
} catch (InterruptedException e) { | ||||||||||||||||||||||||||||||||||||||||||||||
scheduler.shutdownNow(); | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
flush(); // Ensure remaining logs are sent | ||||||||||||||||||||||||||||||||||||||||||||||
super.stop(); | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
public static void addTeamscaleAppenderTo(LoggerContext context, AgentOptions agentOptions) { | ||||||||||||||||||||||||||||||||||||||||||||||
Check warning on line 115 in agent/src/main/java/com/teamscale/jacoco/agent/logging/LogToTeamscaleAppender.java cqse.teamscale.io / teamscale-findingsagent/src/main/java/com/teamscale/jacoco/agent/logging/LogToTeamscaleAppender.java#L115
|
||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add method-level Javadoc. The method /**
* Adds the `LogToTeamscaleAppender` to the specified logger context.
*
* @param context The logger context.
* @param agentOptions The agent options containing Teamscale configuration.
*/
public static void addTeamscaleAppenderTo(LoggerContext context, AgentOptions agentOptions) { ToolsGitHub Check: teamscale-findings
|
||||||||||||||||||||||||||||||||||||||||||||||
LogToTeamscaleAppender logToTeamscaleAppender = new LogToTeamscaleAppender(); | ||||||||||||||||||||||||||||||||||||||||||||||
logToTeamscaleAppender.setContext(context); | ||||||||||||||||||||||||||||||||||||||||||||||
logToTeamscaleAppender.setProfilerId(agentOptions.configurationViaTeamscale.getProfilerId()); | ||||||||||||||||||||||||||||||||||||||||||||||
logToTeamscaleAppender.setTeamscaleClient(agentOptions.createTeamscaleClient()); | ||||||||||||||||||||||||||||||||||||||||||||||
logToTeamscaleAppender.start(); | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
Logger rootLogger = context.getLogger(Logger.ROOT_LOGGER_NAME); | ||||||||||||||||||||||||||||||||||||||||||||||
rootLogger.addAppender(logToTeamscaleAppender); | ||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove unused import.
The import
com.teamscale.client.TeamscaleServer
is not used in the file.- import com.teamscale.client.TeamscaleServer;
Committable suggestion
Tools
GitHub Check: teamscale-findings