[Major] Refactored Operations Log
This commit is contained in:
parent
10ffa01dc9
commit
e644b43e2c
|
@ -1,9 +1,10 @@
|
|||
package li.strolch.handler.operationslog;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import li.strolch.agent.api.StrolchAgent;
|
||||
import li.strolch.model.Locator;
|
||||
import li.strolch.model.Tags.Json;
|
||||
|
@ -13,6 +14,7 @@ import li.strolch.utils.helper.ExceptionHelper;
|
|||
public class LogMessage extends I18nMessage {
|
||||
|
||||
private final String id;
|
||||
private ZonedDateTime zonedDateTime;
|
||||
private final String realm;
|
||||
private final Locator locator;
|
||||
private final LogSeverity severity;
|
||||
|
@ -20,6 +22,7 @@ public class LogMessage extends I18nMessage {
|
|||
public LogMessage(String realm, Locator locator, LogSeverity logSeverity, ResourceBundle bundle, String key) {
|
||||
super(bundle, key);
|
||||
this.id = StrolchAgent.getUniqueId();
|
||||
this.zonedDateTime = ZonedDateTime.now();
|
||||
this.realm = realm;
|
||||
this.locator = locator;
|
||||
this.severity = logSeverity;
|
||||
|
@ -29,6 +32,10 @@ public class LogMessage extends I18nMessage {
|
|||
return this.id;
|
||||
}
|
||||
|
||||
public ZonedDateTime getZonedDateTime() {
|
||||
return this.zonedDateTime;
|
||||
}
|
||||
|
||||
public String getRealm() {
|
||||
return this.realm;
|
||||
}
|
||||
|
@ -57,9 +64,10 @@ public class LogMessage extends I18nMessage {
|
|||
JsonObject jsonObject = new JsonObject();
|
||||
|
||||
jsonObject.addProperty(Json.ID, this.id);
|
||||
jsonObject.addProperty(Json.DATE, this.zonedDateTime.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
|
||||
jsonObject.addProperty(Json.KEY, getKey());
|
||||
jsonObject.addProperty(Json.MESSAGE, formatMessage());
|
||||
jsonObject.addProperty(Json.SEVERITY, this.severity.getSeverity());
|
||||
jsonObject.addProperty(Json.SEVERITY, this.severity.name());
|
||||
jsonObject.addProperty(Json.REALM, this.realm);
|
||||
jsonObject.addProperty(Json.LOCATOR, this.locator.toString());
|
||||
JsonObject values = new JsonObject();
|
||||
|
|
|
@ -1,28 +1,9 @@
|
|||
package li.strolch.handler.operationslog;
|
||||
|
||||
public enum LogSeverity {
|
||||
INFO("Info"), //
|
||||
NOTIFICATION("Notification"), //
|
||||
WARN("Warn"), //
|
||||
ERROR("Error"), //
|
||||
EXCEPTION("Exception");
|
||||
|
||||
private String severity;
|
||||
|
||||
private LogSeverity(String severity) {
|
||||
this.severity = severity;
|
||||
}
|
||||
|
||||
public String getSeverity() {
|
||||
return this.severity;
|
||||
}
|
||||
|
||||
public static LogSeverity from(String value) {
|
||||
for (LogSeverity type : values()) {
|
||||
if (type.severity.equals(value))
|
||||
return type;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("No severity exists for " + value);
|
||||
}
|
||||
Info,
|
||||
Notification,
|
||||
Warning,
|
||||
Error,
|
||||
Exception;
|
||||
}
|
||||
|
|
|
@ -1,14 +1,6 @@
|
|||
package li.strolch.handler.operationslog;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.agent.api.StrolchComponent;
|
||||
|
@ -36,7 +28,7 @@ public class OperationsLog extends StrolchComponent {
|
|||
super.initialize(configuration);
|
||||
}
|
||||
|
||||
public void addMessage(LogMessage logMessage) {
|
||||
public synchronized void addMessage(LogMessage logMessage) {
|
||||
|
||||
// store in global list
|
||||
LinkedHashMap<LogMessage, LogMessage> logMessages = this.logMessagesByRealmAndId
|
||||
|
@ -46,25 +38,25 @@ public class OperationsLog extends StrolchComponent {
|
|||
// store under locator
|
||||
LinkedHashMap<Locator, LinkedHashSet<LogMessage>> logMessagesLocator = this.logMessagesByLocator
|
||||
.computeIfAbsent(logMessage.getRealm(), this::newBoundedLocatorMap);
|
||||
LinkedHashSet<LogMessage> messages = logMessagesLocator.computeIfAbsent(logMessage.getLocator(),
|
||||
(l) -> new LinkedHashSet<LogMessage>());
|
||||
LinkedHashSet<LogMessage> messages = logMessagesLocator
|
||||
.computeIfAbsent(logMessage.getLocator(), (l) -> new LinkedHashSet<>());
|
||||
messages.add(logMessage);
|
||||
}
|
||||
|
||||
public void clearMessages(String realm, Locator locator) {
|
||||
public synchronized void clearMessages(String realm, Locator locator) {
|
||||
LinkedHashMap<Locator, LinkedHashSet<LogMessage>> logMessages = this.logMessagesByLocator.get(realm);
|
||||
if (logMessages != null)
|
||||
logMessages.remove(locator);
|
||||
}
|
||||
|
||||
public Optional<Set<LogMessage>> getMessagesFor(String realm, Locator locator) {
|
||||
public synchronized Optional<Set<LogMessage>> getMessagesFor(String realm, Locator locator) {
|
||||
LinkedHashMap<Locator, LinkedHashSet<LogMessage>> logMessages = this.logMessagesByLocator.get(realm);
|
||||
if (logMessages == null)
|
||||
return Optional.empty();
|
||||
return Optional.ofNullable(logMessages.get(locator));
|
||||
}
|
||||
|
||||
public List<LogMessage> getMessages(String realm) {
|
||||
public synchronized List<LogMessage> getMessages(String realm) {
|
||||
LinkedHashMap<LogMessage, LogMessage> logMessages = this.logMessagesByRealmAndId.get(realm);
|
||||
if (logMessages == null)
|
||||
return Collections.emptyList();
|
||||
|
|
|
@ -1321,7 +1321,7 @@ public abstract class AbstractTransaction implements StrolchTransaction {
|
|||
if (this.operationsLog != null) {
|
||||
this.operationsLog.addMessage(
|
||||
new LogMessage(this.realm.getRealm(), Locator.valueOf(AGENT, "tx", StrolchAgent.getUniqueId()),
|
||||
LogSeverity.EXCEPTION, ResourceBundle.getBundle("strolch-agent"), "agent.tx.failed")
|
||||
LogSeverity.Exception, ResourceBundle.getBundle("strolch-agent"), "agent.tx.failed")
|
||||
.value("reason", e));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,18 +1,21 @@
|
|||
package li.strolch.rest.endpoint;
|
||||
|
||||
import java.util.List;
|
||||
import static java.util.Comparator.comparing;
|
||||
import static li.strolch.utils.helper.StringHelper.isNotEmpty;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import li.strolch.handler.operationslog.LogMessage;
|
||||
import li.strolch.handler.operationslog.LogSeverity;
|
||||
import li.strolch.handler.operationslog.OperationsLog;
|
||||
import li.strolch.rest.RestfulStrolchComponent;
|
||||
import li.strolch.rest.helper.ResponseUtil;
|
||||
|
@ -24,15 +27,47 @@ public class OperationsLogResource {
|
|||
@GET
|
||||
@Path("{realm}")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response getOperationLog(@Context HttpServletRequest request, @QueryParam("offset") int offset,
|
||||
@QueryParam("limit") int limit, @PathParam("realm") String realm) {
|
||||
public Response getOperationLog(@Context HttpServletRequest request, @PathParam("realm") String realm,
|
||||
@QueryParam("offset") int offset, @QueryParam("limit") int limit, @QueryParam("severity") String severityS,
|
||||
@QueryParam("from") String fromS, @QueryParam("to") String toS, @QueryParam("query") String query) {
|
||||
|
||||
// TODO do privilege check
|
||||
|
||||
OperationsLog operationsLog = RestfulStrolchComponent.getInstance().getComponent(OperationsLog.class);
|
||||
List<LogMessage> messages = operationsLog.getMessages(realm);
|
||||
Stream<LogMessage> messages = operationsLog.getMessages(realm).stream();
|
||||
|
||||
Paging<LogMessage> paging = Paging.asPage(messages, offset, limit);
|
||||
if (isNotEmpty(severityS)) {
|
||||
LogSeverity severity = LogSeverity.valueOf(severityS);
|
||||
messages = messages.filter(logMessage -> logMessage.getSeverity() == severity);
|
||||
}
|
||||
|
||||
if (isNotEmpty(query)) {
|
||||
messages = messages.filter(logMessage -> logMessage.getMessage().toLowerCase().contains(query) //
|
||||
|| logMessage.getLocator().getPathElements().contains(query));
|
||||
}
|
||||
|
||||
if (isNotEmpty(fromS) && isNotEmpty(toS)) {
|
||||
|
||||
ZonedDateTime from = LocalDate.parse(fromS).atStartOfDay(ZoneId.systemDefault());
|
||||
ZonedDateTime to = LocalDate.parse(toS).plusDays(1).atStartOfDay(ZoneId.systemDefault());
|
||||
messages = messages.filter(logMessage -> from.isBefore(logMessage.getZonedDateTime()) && to
|
||||
.isAfter(logMessage.getZonedDateTime()));
|
||||
|
||||
} else if (isNotEmpty(fromS)) {
|
||||
|
||||
ZonedDateTime from = LocalDate.parse(fromS).atStartOfDay(ZoneId.systemDefault());
|
||||
messages = messages.filter(logMessage -> from.isBefore(logMessage.getZonedDateTime()));
|
||||
|
||||
} else if (isNotEmpty(toS)) {
|
||||
|
||||
ZonedDateTime to = LocalDate.parse(toS).plusDays(1).atStartOfDay(ZoneId.systemDefault());
|
||||
messages = messages.filter(logMessage -> to.isAfter(logMessage.getZonedDateTime()));
|
||||
|
||||
}
|
||||
|
||||
messages = messages.sorted(comparing(LogMessage::getId).reversed());
|
||||
|
||||
Paging<LogMessage> paging = Paging.asPage(messages.collect(Collectors.toList()), offset, limit);
|
||||
return ResponseUtil.toResponse(paging, LogMessage::toJson);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -163,7 +163,7 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
|
|||
logger.error("Failed to set " + locator + " to execution due to " + e.getMessage(), e);
|
||||
|
||||
if (getContainer().hasComponent(OperationsLog.class)) {
|
||||
getComponent(OperationsLog.class).addMessage(new LogMessage(realm, locator, LogSeverity.EXCEPTION,
|
||||
getComponent(OperationsLog.class).addMessage(new LogMessage(realm, locator, LogSeverity.Exception,
|
||||
ResourceBundle.getBundle("strolch-service"), "execution.handler.failed.execution")
|
||||
.value("reason", e));
|
||||
}
|
||||
|
@ -186,7 +186,7 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
|
|||
logger.error("Failed to set " + locator + " to executed due to " + e.getMessage(), e);
|
||||
|
||||
if (getContainer().hasComponent(OperationsLog.class)) {
|
||||
getComponent(OperationsLog.class).addMessage(new LogMessage(realm, locator, LogSeverity.EXCEPTION,
|
||||
getComponent(OperationsLog.class).addMessage(new LogMessage(realm, locator, LogSeverity.Exception,
|
||||
ResourceBundle.getBundle("strolch-service"), "execution.handler.failed.executed")
|
||||
.value("reason", e));
|
||||
}
|
||||
|
@ -205,7 +205,7 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
|
|||
logger.error("Failed to set " + locator + " to stopped due to " + e.getMessage(), e);
|
||||
|
||||
if (getContainer().hasComponent(OperationsLog.class)) {
|
||||
getComponent(OperationsLog.class).addMessage(new LogMessage(realm, locator, LogSeverity.EXCEPTION,
|
||||
getComponent(OperationsLog.class).addMessage(new LogMessage(realm, locator, LogSeverity.Exception,
|
||||
ResourceBundle.getBundle("strolch-service"), "execution.handler.failed.stopped")
|
||||
.value("reason", e));
|
||||
}
|
||||
|
@ -224,7 +224,7 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
|
|||
logger.error("Failed to set " + locator + " to error due to " + e.getMessage(), e);
|
||||
|
||||
if (getContainer().hasComponent(OperationsLog.class)) {
|
||||
getComponent(OperationsLog.class).addMessage(new LogMessage(realm, locator, LogSeverity.EXCEPTION,
|
||||
getComponent(OperationsLog.class).addMessage(new LogMessage(realm, locator, LogSeverity.Exception,
|
||||
ResourceBundle.getBundle("strolch-service"), "execution.handler.failed.error")
|
||||
.value("reason", e));
|
||||
}
|
||||
|
@ -243,7 +243,7 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
|
|||
logger.error("Failed to set " + locator + " to warning due to " + e.getMessage(), e);
|
||||
|
||||
if (getContainer().hasComponent(OperationsLog.class)) {
|
||||
getComponent(OperationsLog.class).addMessage(new LogMessage(realm, locator, LogSeverity.EXCEPTION,
|
||||
getComponent(OperationsLog.class).addMessage(new LogMessage(realm, locator, LogSeverity.Exception,
|
||||
ResourceBundle.getBundle("strolch-service"), "execution.handler.failed.warning")
|
||||
.value("reason", e));
|
||||
}
|
||||
|
@ -283,7 +283,7 @@ public class EventBasedExecutionHandler extends ExecutionHandler {
|
|||
|
||||
if (getContainer().hasComponent(OperationsLog.class)) {
|
||||
getComponent(OperationsLog.class).addMessage(
|
||||
new LogMessage(realm, activityLoc, LogSeverity.EXCEPTION,
|
||||
new LogMessage(realm, activityLoc, LogSeverity.Exception,
|
||||
ResourceBundle.getBundle("strolch-service"), "execution.handler.failed.archive")
|
||||
.value("reason", e));
|
||||
}
|
||||
|
|
|
@ -10,9 +10,9 @@ import li.strolch.model.activity.Action;
|
|||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
|
||||
/**
|
||||
* The {@link ToErrorReservationExecution} executes same as {@link ReservationExection} with the difference that
|
||||
* {@link #isExecutable(Action)} always returns true, and if the action's resource is currently reserved, the execution
|
||||
* fails and the state is set to ERROR
|
||||
* The {@link ToErrorReservationExecution} executes same as {@link ReservationExection} with the difference that {@link
|
||||
* #isExecutable(Action)} always returns true, and if the action's resource is currently reserved, the execution fails
|
||||
* and the state is set to ERROR
|
||||
*
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
|
@ -44,7 +44,7 @@ public class ToErrorReservationExecution extends ReservationExection {
|
|||
|
||||
if (action.getType().equals(TYPE_RESERVE) && isReserved(action)) {
|
||||
setActionState(action, State.EXECUTION);
|
||||
toError(new LogMessage(tx().getRealmName(), action.getLocator(), LogSeverity.ERROR,
|
||||
toError(new LogMessage(tx().getRealmName(), action.getLocator(), LogSeverity.Error,
|
||||
ResourceBundle.getBundle("strolch-service"), "execution.policy.reservation.alreadyReserved")
|
||||
.value("resourceLoc", getResource(action).getLocator().toString()));
|
||||
} else {
|
||||
|
|
|
@ -145,7 +145,7 @@ public class Migrations {
|
|||
List<Version> list = migrationsRan.getList(realm);
|
||||
for (Version version : list) {
|
||||
LogMessage logMessage = new LogMessage(realm, locator.append(StrolchAgent.getUniqueId()),
|
||||
LogSeverity.INFO, ResourceBundle.getBundle("strolch-service"),
|
||||
LogSeverity.Info, ResourceBundle.getBundle("strolch-service"),
|
||||
"execution.handler.migrations.version").value("version", version.toString());
|
||||
operationsLog.addMessage(logMessage);
|
||||
}
|
||||
|
|
|
@ -202,7 +202,7 @@ public class MigrationsHandler extends StrolchComponent {
|
|||
if (getContainer().hasComponent(OperationsLog.class)) {
|
||||
getComponent(OperationsLog.class).addMessage(
|
||||
new LogMessage(Tags.AGENT, getLocator().append(StrolchAgent.getUniqueId()),
|
||||
LogSeverity.EXCEPTION, ResourceBundle.getBundle("strolch-service"),
|
||||
LogSeverity.Exception, ResourceBundle.getBundle("strolch-service"),
|
||||
"execution.handler.failed.executed").value("reason", e));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ public class I18nMessage {
|
|||
private ResourceBundle bundle;
|
||||
private String key;
|
||||
private Properties values;
|
||||
private String message;
|
||||
|
||||
public I18nMessage(ResourceBundle bundle, String key) {
|
||||
DBC.INTERIM.assertNotNull("bundle must be set!", bundle);
|
||||
|
@ -35,6 +36,10 @@ public class I18nMessage {
|
|||
return this.values;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return formatMessage();
|
||||
}
|
||||
|
||||
public I18nMessage value(String key, String value) {
|
||||
DBC.INTERIM.assertNotEmpty("key must be set!", key);
|
||||
this.values.setProperty(key, value == null ? "-" : value);
|
||||
|
@ -42,13 +47,18 @@ public class I18nMessage {
|
|||
}
|
||||
|
||||
public String formatMessage() {
|
||||
if (this.message != null)
|
||||
return this.message;
|
||||
|
||||
try {
|
||||
String string = this.bundle.getString(this.key);
|
||||
return StringHelper.replacePropertiesIn(this.values, EMPTY, string);
|
||||
this.message = StringHelper.replacePropertiesIn(this.values, EMPTY, string);
|
||||
} catch (MissingResourceException e) {
|
||||
logger.error("Key " + this.key + " is missing in bundle " + this.bundle.getBaseBundleName());
|
||||
return this.key;
|
||||
this.message = this.key;
|
||||
}
|
||||
|
||||
return this.message;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in New Issue