-
Notifications
You must be signed in to change notification settings - Fork 1
Augment logging #41
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
Augment logging #41
Changes from all commits
999a7c1
bf21236
5122152
f653abb
e1dc5ff
1ecb223
c0b9b9a
815452e
abe5333
61bcf73
d6b9a74
048a810
af1f98c
88f363d
fa31a49
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 |
|---|---|---|
|
|
@@ -16,8 +16,11 @@ | |
|
|
||
| import io.grpc.Server; | ||
| import io.grpc.ServerBuilder; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
| public class ConsumerServer implements AutoCloseable { | ||
| private static final Logger logger = LoggerFactory.getLogger(ConsumerServer.class); | ||
|
|
||
| private DataSource ds; | ||
| private ConfigData cfg; | ||
|
|
@@ -40,30 +43,51 @@ public void start(int port) throws IOException, InterruptedException { | |
| } | ||
|
|
||
| public void start(ServerBuilder<?> sb) throws IOException, InterruptedException { | ||
|
Contributor
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. issue (complexity): Consider extracting error-handling and logging into helper methods to keep business logic focused. Consider extracting the error-handling and logging into small helper methods so that your business logic remains focused. For example, you could create an execution wrapper for startup steps: private <T> T executeWithLogging(Supplier<T> supplier, String successMsg, String errorMsg) {
try {
T result = supplier.get();
logger.atInfo().log(successMsg);
return result;
} catch (Exception e) {
logger.atError().setCause(e).log(errorMsg);
throw e;
}
}Then refactor your public void start(ServerBuilder<?> sb) throws IOException, InterruptedException {
logger.atInfo().log("Starting consumer server");
var mb = new EventMessageBroker(asyncExecutor);
var lc = new LocalConsumer<>(cfg, mb);
var grpcServer = new MessageBrokerGrpcServer(mb);
var catchupServer = new CatchupServer(ds);
var catchupService = new CatchupGrpcServer.CatchupServiceImpl(catchupServer);
executeWithLogging(() -> {
lc.start();
server = sb.addService(grpcServer)
.addService(catchupService)
.permitKeepAliveTime(1, TimeUnit.HOURS)
.permitKeepAliveWithoutCalls(true)
.build()
.start();
return null;
}, "Consumer server started successfully", "Failed to start consumer server");
closeables = List.of(lc, mb, asyncExecutor);
}Similarly, for the private void closeResource(AutoCloseable resource) {
try {
resource.close();
} catch (Exception e) {
logger.atWarn()
.setCause(e)
.addArgument(resource.getClass().getSimpleName())
.log("Error closing {}");
}
}
public void stop() {
logger.atInfo().log("Stopping consumer server");
server.shutdown();
for (var c : closeables) {
closeResource(c);
}
logger.atInfo().log("Consumer server stopped");
}These steps separate the business logic from the error-handling and logging concerns, thus reducing nesting and improving clarity while preserving functionality. |
||
| logger.atInfo().log("Starting consumer server"); | ||
|
|
||
| var mb = new EventMessageBroker(asyncExecutor); | ||
| var lc = new LocalConsumer<>(cfg, mb); | ||
| var grpcServer = new MessageBrokerGrpcServer(mb); | ||
| var catchupServer = new CatchupServer(ds); | ||
| var catchupService = new CatchupGrpcServer.CatchupServiceImpl(catchupServer); | ||
| lc.start(); | ||
| server = sb.addService(grpcServer) | ||
| .addService(catchupService) | ||
| .permitKeepAliveTime(1, TimeUnit.HOURS) | ||
| .permitKeepAliveWithoutCalls(true) | ||
| .build() | ||
| .start(); | ||
|
|
||
| try { | ||
| lc.start(); | ||
| server = sb.addService(grpcServer) | ||
| .addService(catchupService) | ||
| .permitKeepAliveTime(1, TimeUnit.HOURS) | ||
| .permitKeepAliveWithoutCalls(true) | ||
| .build() | ||
| .start(); | ||
|
|
||
| logger.atInfo().log("Consumer server started successfully"); | ||
|
|
||
| } catch (Exception e) { | ||
| logger.atError() | ||
| .setCause(e) | ||
| .log("Failed to start consumer server"); | ||
| throw e; | ||
| } | ||
|
|
||
| closeables = List.of(lc, mb, asyncExecutor); | ||
| } | ||
|
|
||
| public void stop() { | ||
| logger.atInfo().log("Stopping consumer server"); | ||
|
|
||
| server.shutdown(); | ||
| for (var c : closeables) { | ||
| try { | ||
| c.close(); | ||
| } catch (Exception e) { | ||
| e.printStackTrace(); | ||
| logger.atWarn() | ||
| .setCause(e) | ||
| .addArgument(c.getClass().getSimpleName()) | ||
| .log("Error closing {}"); | ||
| } | ||
| } | ||
|
|
||
| logger.atInfo().log("Consumer server stopped"); | ||
| } | ||
|
|
||
| @Override | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,8 +14,11 @@ | |
| import java.util.concurrent.TimeUnit; | ||
|
|
||
| import javax.sql.DataSource; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
| public class LocalPersistentConsumer implements AutoCloseable, MessageBroker<TransactionalEvent, TransactionalEvent> { | ||
| private static final Logger logger = LoggerFactory.getLogger(LocalPersistentConsumer.class); | ||
| private PostEventConfig cfg; | ||
| private DataSource ds; | ||
| private AsyncExecutor asyncExecutor; | ||
|
|
@@ -33,35 +36,57 @@ public LocalPersistentConsumer(DataSource ds, PostEventConfig cfg) { | |
| } | ||
|
|
||
| public void start() throws IOException, InterruptedException { | ||
|
Contributor
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. issue (complexity): Consider extracting the startup sequence into a helper method to improve clarity. Consider extracting the startup sequence into its own helper method to reduce nesting and improve method clarity. For example: public void start() throws IOException, InterruptedException {
logger.atInfo().log("Starting local persistent consumer");
if (tb != null) {
logger.atError().log("Local persistent consumer already started");
throw new RuntimeException("Already started");
}
try {
startupSequence();
logger.atInfo().log("Local persistent consumer started successfully");
} catch (Exception e) {
logger.atError().setCause(e).log("Failed to start local persistent consumer");
throw e;
}
}
private void startupSequence() {
tb = new TransactionalBroker(ds, asyncExecutor);
var seb = new SystemEventBroker(asyncExecutor);
var pb = new PersistentBroker<>(tb, ds, seb);
var lc = new LocalConsumer<>(cfg, pb);
seb.subscribe(new CatchupService(ds, new CatchupServer(ds), seb));
var unprocessedSubmitter = new UnprocessedSubmitter(ds, new UnprocessedEventFinder(), tb);
seb.subscribe(unprocessedSubmitter);
asyncExecutor.scheduleAtFixedRate(() -> {
logger.atDebug().log("Triggering unprocessed check");
seb.publish(SystemEvent.UnprocessedCheckRequired);
}, 30, 30, TimeUnit.SECONDS);
lc.start();
closeables = List.of(lc, pb, seb, tb, asyncExecutor);
}This refactoring keeps functionality intact while simplifying the |
||
| if (tb != null) | ||
| throw new RuntimeException("Already started"); | ||
| tb = new TransactionalBroker(ds, asyncExecutor); | ||
| var seb = new SystemEventBroker(asyncExecutor); | ||
| var pb = new PersistentBroker<>(tb, ds, seb); | ||
| var lc = new LocalConsumer<>(cfg, pb); | ||
| seb.subscribe(new CatchupService(ds, new CatchupServer(ds), seb)); | ||
| var unprocessedSubmitter = new UnprocessedSubmitter(ds, new UnprocessedEventFinder(), tb); | ||
| seb.subscribe(unprocessedSubmitter); | ||
|
|
||
| asyncExecutor.scheduleAtFixedRate(() -> { | ||
| seb.publish(SystemEvent.UnprocessedCheckRequired); | ||
| }, 30, 30, TimeUnit.SECONDS); | ||
| logger.atInfo().log("Starting local persistent consumer"); | ||
|
|
||
| lc.start(); | ||
| closeables = List.of(lc, pb, seb, tb, asyncExecutor); | ||
| if (tb != null) { | ||
| logger.atError().log("Local persistent consumer already started"); | ||
| throw new RuntimeException("Already started"); | ||
| } | ||
|
|
||
| try { | ||
|
Contributor
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. suggestion (bug_risk): Consider cleaning up partially initialized resources on startup failure. If an exception occurs within the try block after some components have been successfully initialized, it may leave those resources active. It might be beneficial to include cleanup logic in the catch block to avoid potential resource leaks. Suggested implementation: logger.atInfo().log("Starting local persistent consumer");
if (tb != null) {
logger.atError().log("Local persistent consumer already started");
throw new RuntimeException("Already started");
}
logger.atInfo().log("Starting local persistent consumer");
TransactionalBroker tempTB = null;
SystemEventBroker tempSEB = null;
try {
tempTB = new TransactionalBroker(ds, asyncExecutor);
tempSEB = new SystemEventBroker(asyncExecutor);
tempSEB.subscribe(new CatchupService(ds, catchupClient, tempSEB));
tempSEB.subscribe(new UnprocessedSubmitter(ds, new UnprocessedEventFinder(), tempTB));
asyncExecutor.scheduleAtFixedRate(() -> tempSEB.publish(SystemEvent.UnprocessedCheckRequired), 30, 30, TimeUnit.SECONDS);
tb = tempTB;
} catch (Exception e) {
if (tempTB != null) {
tempTB.close();
}
if (tempSEB != null) {
tempSEB.shutdown();
}
throw e;
}Ensure that both TransactionalBroker and SystemEventBroker have cleanup methods (e.g., close() and shutdown()) or adjust the cleanup calls accordingly. |
||
| tb = new TransactionalBroker(ds, asyncExecutor); | ||
| var seb = new SystemEventBroker(asyncExecutor); | ||
| var pb = new PersistentBroker<>(tb, ds, seb); | ||
| var lc = new LocalConsumer<>(cfg, pb); | ||
|
|
||
| seb.subscribe(new CatchupService(ds, new CatchupServer(ds), seb)); | ||
| var unprocessedSubmitter = new UnprocessedSubmitter(ds, new UnprocessedEventFinder(), tb); | ||
| seb.subscribe(unprocessedSubmitter); | ||
|
|
||
| asyncExecutor.scheduleAtFixedRate(() -> { | ||
| logger.atDebug().log("Triggering unprocessed check"); | ||
| seb.publish(SystemEvent.UnprocessedCheckRequired); | ||
| }, 30, 30, TimeUnit.SECONDS); | ||
|
|
||
| lc.start(); | ||
| closeables = List.of(lc, pb, seb, tb, asyncExecutor); | ||
|
|
||
| logger.atInfo().log("Local persistent consumer started successfully"); | ||
|
|
||
| } catch (Exception e) { | ||
| logger.atError() | ||
| .setCause(e) | ||
| .log("Failed to start local persistent consumer"); | ||
| throw e; | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public void close() { | ||
| for (var c : closeables) { | ||
| logger.atInfo().log("Closing local persistent consumer"); | ||
|
|
||
| for (AutoCloseable c : closeables) { | ||
| try { | ||
| System.out.println("Closing " + c); | ||
| c.close(); | ||
| } catch (Exception e) { | ||
| e.printStackTrace(); | ||
| logger.atWarn() | ||
| .setCause(e) | ||
| .addArgument(c.getClass().getSimpleName()) | ||
| .log("Error closing {}"); | ||
| } | ||
| } | ||
|
|
||
| logger.atInfo().log("Local persistent consumer closed"); | ||
| } | ||
|
|
||
| @Override | ||
|
|
||
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.
issue (complexity): Consider extracting initialization code into a helper method to reduce nesting and repetitive logging.
Consider extracting the initialization code into its own helper method to reduce nesting and repetitive logging. This approach helps in isolating error handling and keeps the
start()method cleaner. For example:This refactoring reduces nesting within
start()and isolates logging and error handling for initialization.