Browse Source

Implementation of Rule Chain and Rule Node debug events

pull/7001/head
Andrii Shvaika 4 years ago
parent
commit
219e97ff4a
  1. 1
      application/src/main/java/org/thingsboard/server/controller/RuleChainController.java
  2. 1
      application/src/test/java/org/thingsboard/server/controller/AbstractRuleEngineControllerTest.java
  3. 47
      common/data/src/main/java/org/thingsboard/server/common/data/event/DebugEventFilter.java
  4. 26
      common/data/src/main/java/org/thingsboard/server/common/data/event/DebugRuleNodeEventFilter.java
  5. 2
      common/data/src/main/java/org/thingsboard/server/common/data/event/ErrorEventFilter.java
  6. 8
      common/data/src/main/java/org/thingsboard/server/common/data/event/Event.java
  7. 6
      common/data/src/main/java/org/thingsboard/server/common/data/event/EventFilter.java
  8. 2
      common/data/src/main/java/org/thingsboard/server/common/data/event/LifeCycleEventFilter.java
  9. 14
      common/data/src/main/java/org/thingsboard/server/common/data/event/RuleChainDebugEvent.java
  10. 17
      common/data/src/main/java/org/thingsboard/server/common/data/event/RuleChainDebugEventFilter.java
  11. 29
      common/data/src/main/java/org/thingsboard/server/common/data/event/RuleNodeDebugEvent.java
  12. 47
      common/data/src/main/java/org/thingsboard/server/common/data/event/RuleNodeDebugEventFilter.java
  13. 2
      common/data/src/main/java/org/thingsboard/server/common/data/event/StatisticsEventFilter.java
  14. 6
      dao/src/main/java/org/thingsboard/server/dao/event/BaseEventService.java
  15. 12
      dao/src/main/java/org/thingsboard/server/dao/event/EventDao.java
  16. 10
      dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java
  17. 1
      dao/src/main/java/org/thingsboard/server/dao/model/sql/AdminSettingsEntity.java
  18. 1
      dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceProfileEntity.java
  19. 9
      dao/src/main/java/org/thingsboard/server/dao/model/sql/ErrorEventEntity.java
  20. 3
      dao/src/main/java/org/thingsboard/server/dao/model/sql/EventEntity.java
  21. 3
      dao/src/main/java/org/thingsboard/server/dao/model/sql/LifecycleEventEntity.java
  22. 63
      dao/src/main/java/org/thingsboard/server/dao/model/sql/RuleChainDebugEventEntity.java
  23. 109
      dao/src/main/java/org/thingsboard/server/dao/model/sql/RuleNodeDebugEventEntity.java
  24. 8
      dao/src/main/java/org/thingsboard/server/dao/model/sql/StatisticsEventEntity.java
  25. 14
      dao/src/main/java/org/thingsboard/server/dao/sql/event/ErrorEventRepository.java
  26. 2
      dao/src/main/java/org/thingsboard/server/dao/sql/event/EventInsertRepository.java
  27. 58
      dao/src/main/java/org/thingsboard/server/dao/sql/event/EventRepository.java
  28. 185
      dao/src/main/java/org/thingsboard/server/dao/sql/event/JpaBaseEventDao.java
  29. 12
      dao/src/main/java/org/thingsboard/server/dao/sql/event/LifecycleEventRepository.java
  30. 82
      dao/src/main/java/org/thingsboard/server/dao/sql/event/RuleChainDebugEventRepository.java
  31. 103
      dao/src/main/java/org/thingsboard/server/dao/sql/event/RuleNodeDebugEventRepository.java
  32. 49
      dao/src/main/java/org/thingsboard/server/dao/sql/event/StatisticsEventRepository.java
  33. 10
      dao/src/main/resources/sql/schema-entities-idx-psql-addon.sql
  34. 6
      dao/src/main/resources/sql/schema-entities.sql
  35. 4
      ui-ngx/src/app/modules/home/components/event/event-table-config.ts
  36. 2
      ui-ngx/src/app/shared/models/event.models.ts

1
application/src/main/java/org/thingsboard/server/controller/RuleChainController.java

@ -39,7 +39,6 @@ import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.rule.engine.api.ScriptEngine;
import org.thingsboard.server.actors.ActorSystemContext;
import org.thingsboard.server.actors.tenant.DebugTbRateLimits;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.EventInfo;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.edge.Edge;

1
application/src/test/java/org/thingsboard/server/controller/AbstractRuleEngineControllerTest.java

@ -19,7 +19,6 @@ import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.TestPropertySource;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.EventInfo;
import org.thingsboard.server.common.data.event.EventType;
import org.thingsboard.server.common.data.id.EntityId;

47
common/data/src/main/java/org/thingsboard/server/common/data/event/DebugEventFilter.java

@ -0,0 +1,47 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.event;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.data.domain.Page;
import org.springframework.data.repository.query.Param;
import org.thingsboard.server.common.data.StringUtils;
import java.util.UUID;
@Data
@ApiModel
public abstract class DebugEventFilter implements EventFilter {
@ApiModelProperty(position = 1, value = "String value representing the server name, identifier or ip address where the platform is running", example = "ip-172-31-24-152")
protected String server;
@ApiModelProperty(position = 10, value = "Boolean value to filter the errors", allowableValues = "false, true")
protected boolean isError;
@ApiModelProperty(position = 11, value = "The case insensitive 'contains' filter based on error message", example = "not present in the DB")
protected String errorStr;
public void setIsError(boolean isError) {
this.isError = isError;
}
@Override
public boolean isNotEmpty() {
return !StringUtils.isEmpty(server) || isError || !StringUtils.isEmpty(errorStr);
}
}

26
common/data/src/main/java/org/thingsboard/server/common/data/event/DebugRuleNodeEventFilter.java

@ -1,26 +0,0 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.event;
import io.swagger.annotations.ApiModel;
@ApiModel
public class DebugRuleNodeEventFilter extends DebugEvent {
@Override
public EventType getEventType() {
return EventType.DEBUG_RULE_NODE;
}
}

2
common/data/src/main/java/org/thingsboard/server/common/data/event/ErrorEventFilter.java

@ -37,7 +37,7 @@ public class ErrorEventFilter implements EventFilter {
}
@Override
public boolean hasFilterForJsonBody() {
public boolean isNotEmpty() {
return !StringUtils.isEmpty(server) || !StringUtils.isEmpty(method) || !StringUtils.isEmpty(errorStr);
}
}

8
common/data/src/main/java/org/thingsboard/server/common/data/event/Event.java

@ -16,6 +16,7 @@
package org.thingsboard.server.common.data.event;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.BaseData;
@ -56,8 +57,15 @@ public abstract class Event extends BaseData<EventId> {
eventInfo.setEntityId(EntityIdFactory.getByTypeAndUuid(entityType, entityId));
eventInfo.setType(getType().getOldName());
eventInfo.setId(id);
eventInfo.setUid(id.toString());
eventInfo.setCreatedTime(createdTime);
eventInfo.setBody(OBJECT_MAPPER.createObjectNode().put("server", getServiceId()));
return eventInfo;
}
protected static void putNotNull(ObjectNode json, String key, String value) {
if (value != null) {
json.put(key, value);
}
}
}

6
common/data/src/main/java/org/thingsboard/server/common/data/event/EventFilter.java

@ -26,8 +26,8 @@ import io.swagger.annotations.ApiModelProperty;
include = JsonTypeInfo.As.PROPERTY,
property = "eventType")
@JsonSubTypes({
@JsonSubTypes.Type(value = DebugRuleNodeEventFilter.class, name = "DEBUG_RULE_NODE"),
@JsonSubTypes.Type(value = DebugRuleChainEventFilter.class, name = "DEBUG_RULE_CHAIN"),
@JsonSubTypes.Type(value = RuleNodeDebugEventFilter.class, name = "DEBUG_RULE_NODE"),
@JsonSubTypes.Type(value = RuleChainDebugEventFilter.class, name = "DEBUG_RULE_CHAIN"),
@JsonSubTypes.Type(value = ErrorEventFilter.class, name = "ERROR"),
@JsonSubTypes.Type(value = LifeCycleEventFilter.class, name = "LC_EVENT"),
@JsonSubTypes.Type(value = StatisticsEventFilter.class, name = "STATS")
@ -37,6 +37,6 @@ public interface EventFilter {
@ApiModelProperty(position = 1, required = true, value = "String value representing the event type", example = "STATS")
EventType getEventType();
boolean hasFilterForJsonBody();
boolean isNotEmpty();
}

2
common/data/src/main/java/org/thingsboard/server/common/data/event/LifeCycleEventFilter.java

@ -39,7 +39,7 @@ public class LifeCycleEventFilter implements EventFilter {
}
@Override
public boolean hasFilterForJsonBody() {
public boolean isNotEmpty() {
return !StringUtils.isEmpty(server) || !StringUtils.isEmpty(event) || !StringUtils.isEmpty(status) || !StringUtils.isEmpty(errorStr);
}
}

14
common/data/src/main/java/org/thingsboard/server/common/data/event/RuleChainDebugEvent.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.common.data.event;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
@ -22,7 +23,6 @@ import lombok.Setter;
import lombok.ToString;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.EventInfo;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import java.util.UUID;
@ -40,9 +40,11 @@ public class RuleChainDebugEvent extends Event {
this.error = error;
}
@Getter @Setter
@Getter
@Setter
private String message;
@Getter @Setter
@Getter
@Setter
private String error;
@Override
@ -52,6 +54,10 @@ public class RuleChainDebugEvent extends Event {
@Override
public EventInfo toInfo(EntityType entityType) {
return null;
EventInfo eventInfo = super.toInfo(entityType);
var json = (ObjectNode) eventInfo.getBody();
putNotNull(json, "message", message);
putNotNull(json, "error", error);
return eventInfo;
}
}

17
common/data/src/main/java/org/thingsboard/server/common/data/event/DebugRuleChainEventFilter.java → common/data/src/main/java/org/thingsboard/server/common/data/event/RuleChainDebugEventFilter.java

@ -16,11 +16,26 @@
package org.thingsboard.server.common.data.event;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.StringUtils;
@Data
@EqualsAndHashCode(callSuper = true)
@ApiModel
public class DebugRuleChainEventFilter extends DebugEvent {
public class RuleChainDebugEventFilter extends DebugEventFilter {
@ApiModelProperty(position = 2, value = "String value representing the message")
protected String message;
@Override
public EventType getEventType() {
return EventType.DEBUG_RULE_CHAIN;
}
@Override
public boolean isNotEmpty() {
return super.isNotEmpty() || !StringUtils.isEmpty(message);
}
}

29
common/data/src/main/java/org/thingsboard/server/common/data/event/RuleNodeDebugEvent.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.common.data.event;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
@ -62,14 +63,16 @@ public class RuleNodeDebugEvent extends Event {
private final String dataType;
@Getter
private final String relationType;
@Getter @Setter
@Getter
@Setter
private String data;
@Getter @Setter
@Getter
@Setter
private String metadata;
@Getter @Setter
@Getter
@Setter
private String error;
//TODO: rename the enum constant
@Override
public EventType getType() {
return EventType.DEBUG_RULE_NODE;
@ -77,6 +80,22 @@ public class RuleNodeDebugEvent extends Event {
@Override
public EventInfo toInfo(EntityType entityType) {
return null;
EventInfo eventInfo = super.toInfo(entityType);
var json = (ObjectNode) eventInfo.getBody();
json.put("type", eventType);
if (eventEntity != null) {
json.put("entityId", eventEntity.getId().toString()).put("entityType", eventEntity.getEntityType().name());
}
if (msgId != null) {
json.put("msgId", msgId.toString());
}
putNotNull(json, "msgType", msgType);
putNotNull(json, "dataType", dataType);
putNotNull(json, "relationType", relationType);
putNotNull(json, "data", data);
putNotNull(json, "metadata", metadata);
putNotNull(json, "error", error);
return eventInfo;
}
}

47
common/data/src/main/java/org/thingsboard/server/common/data/event/DebugEvent.java → common/data/src/main/java/org/thingsboard/server/common/data/event/RuleNodeDebugEventFilter.java

@ -18,41 +18,40 @@ package org.thingsboard.server.common.data.event;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.StringUtils;
@Data
@EqualsAndHashCode(callSuper = true)
@ApiModel
public abstract class DebugEvent implements EventFilter {
public class RuleNodeDebugEventFilter extends DebugEventFilter {
@ApiModelProperty(position = 1, value = "String value representing msg direction type (incoming to entity or outcoming from entity)", allowableValues = "IN, OUT")
@ApiModelProperty(position = 2, value = "String value representing msg direction type (incoming to entity or outcoming from entity)", allowableValues = "IN, OUT")
protected String msgDirectionType;
@ApiModelProperty(position = 2, value = "String value representing the server name, identifier or ip address where the platform is running", example = "ip-172-31-24-152")
protected String server;
@ApiModelProperty(position = 3, value = "The case insensitive 'contains' filter based on data (key and value) for the message.", example = "humidity")
protected String dataSearch;
@ApiModelProperty(position = 4, value = "The case insensitive 'contains' filter based on metadata (key and value) for the message.", example = "deviceName")
protected String metadataSearch;
@ApiModelProperty(position = 5, value = "String value representing the entity type", allowableValues = "DEVICE")
protected String entityName;
@ApiModelProperty(position = 6, value = "String value representing the type of message routing", example = "Success")
protected String relationType;
@ApiModelProperty(position = 7, value = "String value representing the entity id in the event body (originator of the message)", example = "de9d54a0-2b7a-11ec-a3cc-23386423d98f")
@ApiModelProperty(position = 3, value = "String value representing the entity id in the event body (originator of the message)", example = "de9d54a0-2b7a-11ec-a3cc-23386423d98f")
protected String entityId;
@ApiModelProperty(position = 8, value = "String value representing the message type", example = "POST_TELEMETRY_REQUEST")
@ApiModelProperty(position = 4, value = "String value representing the entity type", allowableValues = "DEVICE")
protected String entityType;
@ApiModelProperty(position = 5, value = "String value representing the message id in the rule engine", example = "de9d54a0-2b7a-11ec-a3cc-23386423d98f")
protected String msgId;
@ApiModelProperty(position = 6, value = "String value representing the message type", example = "POST_TELEMETRY_REQUEST")
protected String msgType;
@ApiModelProperty(position = 9, value = "Boolean value to filter the errors", allowableValues = "false, true")
protected boolean isError;
@ApiModelProperty(position = 10, value = "The case insensitive 'contains' filter based on error message", example = "not present in the DB")
protected String errorStr;
@ApiModelProperty(position = 7, value = "String value representing the type of message routing", example = "Success")
protected String relationType;
@ApiModelProperty(position = 8, value = "The case insensitive 'contains' filter based on data (key and value) for the message.", example = "humidity")
protected String dataSearch;
@ApiModelProperty(position = 9, value = "The case insensitive 'contains' filter based on metadata (key and value) for the message.", example = "deviceName")
protected String metadataSearch;
public void setIsError(boolean isError) {
this.isError = isError;
@Override
public EventType getEventType() {
return EventType.DEBUG_RULE_NODE;
}
@Override
public boolean hasFilterForJsonBody() {
return !StringUtils.isEmpty(msgDirectionType) || !StringUtils.isEmpty(server) || !StringUtils.isEmpty(dataSearch) || !StringUtils.isEmpty(metadataSearch)
|| !StringUtils.isEmpty(entityName) || !StringUtils.isEmpty(relationType) || !StringUtils.isEmpty(entityId) || !StringUtils.isEmpty(msgType) || !StringUtils.isEmpty(errorStr) || isError;
public boolean isNotEmpty() {
return super.isNotEmpty() || !StringUtils.isEmpty(msgDirectionType) || !StringUtils.isEmpty(entityId)
|| !StringUtils.isEmpty(entityType) || !StringUtils.isEmpty(msgId) || !StringUtils.isEmpty(msgType) ||
!StringUtils.isEmpty(relationType) || !StringUtils.isEmpty(dataSearch) || !StringUtils.isEmpty(metadataSearch);
}
}

2
common/data/src/main/java/org/thingsboard/server/common/data/event/StatisticsEventFilter.java

@ -37,7 +37,7 @@ public class StatisticsEventFilter implements EventFilter {
}
@Override
public boolean hasFilterForJsonBody() {
public boolean isNotEmpty() {
return !StringUtils.isEmpty(server) || (messagesProcessed != null && messagesProcessed > 0) || (errorsOccurred != null && errorsOccurred > 0);
}
}

6
dao/src/main/java/org/thingsboard/server/dao/event/BaseEventService.java

@ -102,7 +102,7 @@ public class BaseEventService implements EventService {
@Override
public List<EventInfo> findLatestEvents(TenantId tenantId, EntityId entityId, EventType eventType, int limit) {
return eventDao.findLatestEvents(tenantId.getId(), entityId.getId(), eventType, limit);
return convert(entityId.getEntityType(), eventDao.findLatestEvents(tenantId.getId(), entityId.getId(), eventType, limit));
}
@Override
@ -142,4 +142,8 @@ public class BaseEventService implements EventService {
pd.getData().stream().map(e -> e.toInfo(entityType)).collect(Collectors.toList())
, pd.getTotalPages(), pd.getTotalElements(), pd.hasNext());
}
private List<EventInfo> convert(EntityType entityType, List<? extends Event> list) {
return list == null ? null : list.stream().map(e -> e.toInfo(entityType)).collect(Collectors.toList());
}
}

12
dao/src/main/java/org/thingsboard/server/dao/event/EventDao.java

@ -41,16 +41,6 @@ public interface EventDao {
*/
ListenableFuture<Void> saveAsync(Event event);
/**
* Find events by tenantId, entityId and pageLink.
*
* @param tenantId the tenantId
* @param entityId the entityId
* @param pageLink the pageLink
* @return the event list
*/
PageData<EventInfo> findEvents(UUID tenantId, EntityId entityId, TimePageLink pageLink);
/**
* Find events by tenantId, entityId, eventType and pageLink.
*
@ -73,7 +63,7 @@ public interface EventDao {
* @param limit the limit
* @return the event list
*/
List<EventInfo> findLatestEvents(UUID tenantId, UUID entityId, EventType eventType, int limit);
List<? extends Event> findLatestEvents(UUID tenantId, UUID entityId, EventType eventType, int limit);
/**
* Executes stored procedure to cleanup old events. Uses separate ttl for debug and other events.

10
dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java

@ -388,6 +388,16 @@ public class ModelConstants {
public static final String EVENT_ERROR_COLUMN_NAME = "e_error";
public static final String EVENT_SUCCESS_COLUMN_NAME = "e_success";
public static final String EVENT_ENTITY_ID_COLUMN_NAME = "e_entity_id";
public static final String EVENT_ENTITY_TYPE_COLUMN_NAME = "e_entity_type";
public static final String EVENT_MSG_ID_COLUMN_NAME = "e_msg_id";
public static final String EVENT_MSG_TYPE_COLUMN_NAME = "e_msg_type";
public static final String EVENT_DATA_TYPE_COLUMN_NAME = "e_data_type";
public static final String EVENT_RELATION_TYPE_COLUMN_NAME = "e_relation_type";
public static final String EVENT_DATA_COLUMN_NAME = "e_data";
public static final String EVENT_METADATA_COLUMN_NAME = "e_metadata";
public static final String EVENT_MESSAGE_COLUMN_NAME = "e_message";
public static final String DEBUG_MODE = "debug_mode";
/**

1
dao/src/main/java/org/thingsboard/server/dao/model/sql/AdminSettingsEntity.java

@ -31,7 +31,6 @@ import org.thingsboard.server.dao.util.mapping.JsonStringType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import java.util.UUID;
import static org.thingsboard.server.dao.model.ModelConstants.ADMIN_SETTINGS_COLUMN_FAMILY_NAME;

1
dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceProfileEntity.java

@ -30,7 +30,6 @@ import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.OtaPackageId;
import org.thingsboard.server.common.data.id.QueueId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.model.BaseSqlEntity;

9
dao/src/main/java/org/thingsboard/server/dao/model/sql/ErrorEventEntity.java

@ -18,30 +18,21 @@ package org.thingsboard.server.dao.model.sql;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.TypeDef;
import org.thingsboard.server.common.data.event.ErrorEvent;
import org.thingsboard.server.common.data.event.StatisticsEvent;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.model.BaseEntity;
import org.thingsboard.server.dao.util.mapping.JsonStringType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import java.util.UUID;
import static org.thingsboard.server.dao.model.ModelConstants.ERROR_EVENT_TABLE_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.EVENT_ERROR_COLUMN_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.EVENT_METHOD_COLUMN_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.EVENT_SUCCESS_COLUMN_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.EVENT_TYPE_COLUMN_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.STATS_EVENT_TABLE_NAME;
@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@TypeDef(name = "json", typeClass = JsonStringType.class)
@Table(name = ERROR_EVENT_TABLE_NAME)
@NoArgsConstructor
public class ErrorEventEntity extends EventEntity<ErrorEvent> implements BaseEntity<ErrorEvent> {

3
dao/src/main/java/org/thingsboard/server/dao/model/sql/EventEntity.java

@ -17,11 +17,9 @@ package org.thingsboard.server.dao.model.sql;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.TypeDef;
import org.thingsboard.server.common.data.event.Event;
import org.thingsboard.server.dao.model.BaseEntity;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.dao.util.mapping.JsonStringType;
import javax.persistence.Column;
import javax.persistence.Id;
@ -34,7 +32,6 @@ import static org.thingsboard.server.dao.model.ModelConstants.EVENT_TENANT_ID_PR
import static org.thingsboard.server.dao.model.ModelConstants.TS_COLUMN;
@Data
@TypeDef(name = "json", typeClass = JsonStringType.class)
@NoArgsConstructor
@MappedSuperclass
public abstract class EventEntity<T extends Event> implements BaseEntity<T> {

3
dao/src/main/java/org/thingsboard/server/dao/model/sql/LifecycleEventEntity.java

@ -18,11 +18,9 @@ package org.thingsboard.server.dao.model.sql;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.TypeDef;
import org.thingsboard.server.common.data.event.LifecycleEvent;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.model.BaseEntity;
import org.thingsboard.server.dao.util.mapping.JsonStringType;
import javax.persistence.Column;
import javax.persistence.Entity;
@ -36,7 +34,6 @@ import static org.thingsboard.server.dao.model.ModelConstants.LC_EVENT_TABLE_NAM
@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@TypeDef(name = "json", typeClass = JsonStringType.class)
@Table(name = LC_EVENT_TABLE_NAME)
@NoArgsConstructor
public class LifecycleEventEntity extends EventEntity<LifecycleEvent> implements BaseEntity<LifecycleEvent> {

63
dao/src/main/java/org/thingsboard/server/dao/model/sql/RuleChainDebugEventEntity.java

@ -0,0 +1,63 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.model.sql;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.thingsboard.server.common.data.event.RuleChainDebugEvent;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.model.BaseEntity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import static org.thingsboard.server.dao.model.ModelConstants.EVENT_ERROR_COLUMN_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.EVENT_MESSAGE_COLUMN_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.RULE_CHAIN_DEBUG_EVENT_TABLE_NAME;
@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = RULE_CHAIN_DEBUG_EVENT_TABLE_NAME)
@NoArgsConstructor
public class RuleChainDebugEventEntity extends EventEntity<RuleChainDebugEvent> implements BaseEntity<RuleChainDebugEvent> {
@Column(name = EVENT_MESSAGE_COLUMN_NAME)
private String message;
@Column(name = EVENT_ERROR_COLUMN_NAME)
private String error;
public RuleChainDebugEventEntity(RuleChainDebugEvent event) {
super(event);
this.message = event.getMessage();
this.error = event.getError();
}
@Override
public RuleChainDebugEvent toData() {
return RuleChainDebugEvent.builder()
.tenantId(TenantId.fromUUID(tenantId))
.entityId(entityId)
.serviceId(serviceId)
.id(id)
.ts(ts)
.message(message)
.error(error).build();
}
}

109
dao/src/main/java/org/thingsboard/server/dao/model/sql/RuleNodeDebugEventEntity.java

@ -0,0 +1,109 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.model.sql;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.thingsboard.server.common.data.event.RuleNodeDebugEvent;
import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.model.BaseEntity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import java.util.UUID;
import static org.thingsboard.server.dao.model.ModelConstants.EVENT_DATA_COLUMN_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.EVENT_DATA_TYPE_COLUMN_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.EVENT_ENTITY_ID_COLUMN_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.EVENT_ENTITY_TYPE_COLUMN_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.EVENT_ERROR_COLUMN_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.EVENT_METADATA_COLUMN_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.EVENT_MSG_ID_COLUMN_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.EVENT_MSG_TYPE_COLUMN_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.EVENT_RELATION_TYPE_COLUMN_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.EVENT_TYPE_COLUMN_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.RULE_NODE_DEBUG_EVENT_TABLE_NAME;
@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = RULE_NODE_DEBUG_EVENT_TABLE_NAME)
@NoArgsConstructor
public class RuleNodeDebugEventEntity extends EventEntity<RuleNodeDebugEvent> implements BaseEntity<RuleNodeDebugEvent> {
@Column(name = EVENT_TYPE_COLUMN_NAME)
private String eventType;
@Column(name = EVENT_ENTITY_ID_COLUMN_NAME)
private UUID eventEntityId;
@Column(name = EVENT_ENTITY_TYPE_COLUMN_NAME)
private String eventEntityType;
@Column(name = EVENT_MSG_ID_COLUMN_NAME)
private UUID msgId;
@Column(name = EVENT_MSG_TYPE_COLUMN_NAME)
private String msgType;
@Column(name = EVENT_DATA_TYPE_COLUMN_NAME)
private String dataType;
@Column(name = EVENT_RELATION_TYPE_COLUMN_NAME)
private String relationType;
@Column(name = EVENT_DATA_COLUMN_NAME)
private String data;
@Column(name = EVENT_METADATA_COLUMN_NAME)
private String metadata;
@Column(name = EVENT_ERROR_COLUMN_NAME)
private String error;
public RuleNodeDebugEventEntity(RuleNodeDebugEvent event) {
super(event);
this.eventType = event.getEventType();
if (event.getEventEntity() != null) {
this.eventEntityId = event.getEventEntity().getId();
this.eventEntityType = event.getEventEntity().getEntityType().name();
}
this.msgId = event.getMsgId();
this.msgType = event.getMsgType();
this.dataType = event.getDataType();
this.relationType = event.getRelationType();
this.data = event.getData();
this.metadata = event.getMetadata();
this.error = event.getError();
}
@Override
public RuleNodeDebugEvent toData() {
var builder = RuleNodeDebugEvent.builder()
.tenantId(TenantId.fromUUID(tenantId))
.entityId(entityId)
.serviceId(serviceId)
.id(id)
.ts(ts)
.eventType(eventType)
.msgId(msgId)
.msgType(msgType)
.dataType(dataType)
.relationType(relationType)
.data(data)
.metadata(metadata)
.error(error);
if (eventEntityId != null) {
builder.eventEntity(EntityIdFactory.getByTypeAndUuid(eventEntityType, eventEntityId));
}
return builder.build();
}
}

8
dao/src/main/java/org/thingsboard/server/dao/model/sql/StatisticsEventEntity.java

@ -18,29 +18,21 @@ package org.thingsboard.server.dao.model.sql;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.TypeDef;
import org.thingsboard.server.common.data.event.LifecycleEvent;
import org.thingsboard.server.common.data.event.StatisticsEvent;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.model.BaseEntity;
import org.thingsboard.server.dao.util.mapping.JsonStringType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import static org.thingsboard.server.dao.model.ModelConstants.EVENT_ERRORS_OCCURRED_COLUMN_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.EVENT_ERROR_COLUMN_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.EVENT_MESSAGES_PROCESSED_COLUMN_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.EVENT_SUCCESS_COLUMN_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.EVENT_TYPE_COLUMN_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.LC_EVENT_TABLE_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.STATS_EVENT_TABLE_NAME;
@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@TypeDef(name = "json", typeClass = JsonStringType.class)
@Table(name = STATS_EVENT_TABLE_NAME)
@NoArgsConstructor
public class StatisticsEventEntity extends EventEntity<StatisticsEvent> implements BaseEntity<StatisticsEvent> {

14
dao/src/main/java/org/thingsboard/server/dao/sql/event/ErrorEventRepository.java

@ -20,17 +20,23 @@ import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.thingsboard.server.common.data.event.ErrorEvent;
import org.thingsboard.server.common.data.event.LifecycleEvent;
import org.thingsboard.server.dao.model.sql.ErrorEventEntity;
import org.thingsboard.server.dao.model.sql.LifecycleEventEntity;
import org.thingsboard.server.dao.model.sql.StatisticsEventEntity;
import java.util.List;
import java.util.UUID;
/**
* Created by Valerii Sosliuk on 5/3/2017.
*/
public interface ErrorEventRepository extends JpaRepository<ErrorEventEntity, UUID> {
public interface ErrorEventRepository extends EventRepository<ErrorEventEntity, ErrorEvent>, JpaRepository<ErrorEventEntity, UUID> {
@Override
@Query("SELECT e FROM ErrorEventEntity e WHERE e.tenantId = :tenantId AND e.entityId = :entityId ORDER BY e.ts DESC")
List<ErrorEventEntity> findLatestEvents(UUID tenantId, UUID entityId, int limit);
@Override
@Query("SELECT e FROM ErrorEventEntity e WHERE " +
"e.tenantId = :tenantId " +
"AND e.entityId = :entityId " +

2
dao/src/main/java/org/thingsboard/server/dao/sql/event/EventInsertRepository.java

@ -15,8 +15,6 @@
*/
package org.thingsboard.server.dao.sql.event;
import org.jetbrains.annotations.NotNull;
import org.postgresql.core.Oid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;

58
dao/src/main/java/org/thingsboard/server/dao/sql/event/EventRepository.java

@ -21,6 +21,8 @@ import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.EventInfo;
import org.thingsboard.server.common.data.event.Event;
import org.thingsboard.server.dao.model.sql.EventEntity;
import java.util.List;
@ -29,58 +31,12 @@ import java.util.UUID;
/**
* Created by Valerii Sosliuk on 5/3/2017.
*/
public interface EventRepository extends JpaRepository<EventEntity, UUID> {
public interface EventRepository<T extends EventEntity<V>, V extends Event> {
List<T> findLatestEvents(UUID tenantId, UUID entityId, int limit);
Page<T> findEvents(UUID tenantId, UUID entityId, Long startTime, Long endTime, Pageable pageable);
// EventEntity findByTenantIdAndEntityTypeAndEntityIdAndEventTypeAndEventUid(UUID tenantId,
// EntityType entityType,
// UUID entityId,
// String eventType,
// String eventUid);
//
// EventEntity findByTenantIdAndEntityTypeAndEntityId(UUID tenantId,
// EntityType entityType,
// UUID entityId);
//
// @Query("SELECT e FROM EventEntity e WHERE e.tenantId = :tenantId AND e.entityType = :entityType " +
// "AND e.entityId = :entityId AND e.eventType = :eventType ORDER BY e.eventType DESC, e.id DESC")
// List<EventEntity> findLatestByTenantIdAndEntityTypeAndEntityIdAndEventType(
// @Param("tenantId") UUID tenantId,
// @Param("entityType") EntityType entityType,
// @Param("entityId") UUID entityId,
// @Param("eventType") String eventType,
// Pageable pageable);
//
// @Query("SELECT e FROM EventEntity e WHERE " +
// "e.tenantId = :tenantId " +
// "AND e.entityType = :entityType AND e.entityId = :entityId " +
// "AND (:startTime IS NULL OR e.createdTime >= :startTime) " +
// "AND (:endTime IS NULL OR e.createdTime <= :endTime) " +
// "AND LOWER(e.eventType) LIKE LOWER(CONCAT('%', :textSearch, '%'))"
// )
// Page<EventEntity> findEventsByTenantIdAndEntityId(@Param("tenantId") UUID tenantId,
// @Param("entityType") EntityType entityType,
// @Param("entityId") UUID entityId,
// @Param("textSearch") String textSearch,
// @Param("startTime") Long startTime,
// @Param("endTime") Long endTime,
// Pageable pageable);
//
//
//
// @Query("SELECT e FROM EventEntity e WHERE " +
// "e.tenantId = :tenantId " +
// "AND e.entityType = :entityType AND e.entityId = :entityId " +
// "AND e.eventType = :eventType " +
// "AND (:startTime IS NULL OR e.createdTime >= :startTime) " +
// "AND (:endTime IS NULL OR e.createdTime <= :endTime)"
// )
// Page<EventEntity> findEventsByTenantIdAndEntityIdAndEventType(@Param("tenantId") UUID tenantId,
// @Param("entityType") EntityType entityType,
// @Param("entityId") UUID entityId,
// @Param("eventType") String eventType,
// @Param("startTime") Long startTime,
// @Param("endTime") Long endTime,
// Pageable pageable);
//
// @Query(nativeQuery = true,
// value = "SELECT e.id, e.created_time, e.body, e.entity_id, e.entity_type, e.event_type, e.event_uid, e.tenant_id, ts FROM " +

185
dao/src/main/java/org/thingsboard/server/dao/sql/event/JpaBaseEventDao.java

@ -23,25 +23,22 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EventInfo;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.event.DebugEvent;
import org.thingsboard.server.common.data.event.ErrorEvent;
import org.thingsboard.server.common.data.event.RuleChainDebugEventFilter;
import org.thingsboard.server.common.data.event.RuleNodeDebugEventFilter;
import org.thingsboard.server.common.data.event.ErrorEventFilter;
import org.thingsboard.server.common.data.event.Event;
import org.thingsboard.server.common.data.event.EventFilter;
import org.thingsboard.server.common.data.event.EventType;
import org.thingsboard.server.common.data.event.LifeCycleEventFilter;
import org.thingsboard.server.common.data.event.LifecycleEvent;
import org.thingsboard.server.common.data.event.StatisticsEvent;
import org.thingsboard.server.common.data.event.StatisticsEventFilter;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EventId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.stats.StatsFactory;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.event.EventDao;
import org.thingsboard.server.dao.model.sql.EventEntity;
import org.thingsboard.server.dao.sql.ScheduledLogExecutorComponent;
import org.thingsboard.server.dao.sql.TbSqlBlockingQueueParams;
import org.thingsboard.server.dao.sql.TbSqlBlockingQueueWrapper;
@ -51,6 +48,7 @@ import org.thingsboard.server.dao.timeseries.SqlPartition;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@ -74,9 +72,6 @@ public class JpaBaseEventDao implements EventDao {
@Autowired
private SqlPartitioningRepository partitioningRepository;
@Autowired
private EventRepository eventRepository;
@Autowired
private LifecycleEventRepository lcEventRepository;
@ -92,6 +87,12 @@ public class JpaBaseEventDao implements EventDao {
@Autowired
private EventCleanupRepository eventCleanupRepository;
@Autowired
private RuleNodeDebugEventRepository ruleNodeDebugEventRepository;
@Autowired
private RuleChainDebugEventRepository ruleChainDebugEventRepository;
@Autowired
ScheduledLogExecutorComponent logExecutor;
@ -115,6 +116,8 @@ public class JpaBaseEventDao implements EventDao {
private TbSqlBlockingQueueWrapper<Event> queue;
private final Map<EventType, EventRepository<?, ?>> repositories = new ConcurrentHashMap<>();
@PostConstruct
private void init() {
for (EventType eventType : EventType.values()) {
@ -131,6 +134,11 @@ public class JpaBaseEventDao implements EventDao {
Function<Event, Integer> hashcodeFunction = entity -> Objects.hash(super.hashCode(), entity.getTenantId(), entity.getEntityId());
queue = new TbSqlBlockingQueueWrapper<>(params, hashcodeFunction, batchThreads, statsFactory);
queue.init(logExecutor, v -> eventInsertRepository.save(v), Comparator.comparing(Event::getCreatedTime));
repositories.put(EventType.LC_EVENT, lcEventRepository);
repositories.put(EventType.STATS, statsEventRepository);
repositories.put(EventType.ERROR, errorEventRepository);
repositories.put(EventType.DEBUG_RULE_NODE, ruleNodeDebugEventRepository);
repositories.put(EventType.DEBUG_RULE_CHAIN, ruleChainDebugEventRepository);
}
@PreDestroy
@ -190,58 +198,19 @@ public class JpaBaseEventDao implements EventDao {
}
}
@Override
public PageData<EventInfo> findEvents(UUID tenantId, EntityId entityId, TimePageLink pageLink) {
return null;
// return DaoUtil.toPageData(
// eventRepository
// .findEventsByTenantIdAndEntityId(
// tenantId,
// entityId.getEntityType(),
// entityId.getId(),
// Objects.toString(pageLink.getTextSearch(), ""),
// pageLink.getStartTime(),
// pageLink.getEndTime(),
// DaoUtil.toPageable(pageLink)));
}
@Override
public PageData<? extends Event> findEvents(UUID tenantId, UUID entityId, EventType eventType, TimePageLink pageLink) {
switch (eventType) {
case LC_EVENT:
return findLcEventsWithoutFilter(tenantId, entityId, pageLink);
case STATS:
return findStatsEventsWithoutFilter(tenantId, entityId, pageLink);
case ERROR:
return findErrorEventsWithoutFilter(tenantId, entityId, pageLink);
default:
throw new RuntimeException("Event type: " + eventType + " is not supported!");
}
return DaoUtil.toPageData(getEventRepository(eventType).findEvents(tenantId, entityId, pageLink.getStartTime(), pageLink.getEndTime(), DaoUtil.toPageable(pageLink)));
}
private PageData<LifecycleEvent> findLcEventsWithoutFilter(UUID tenantId, UUID entityId, TimePageLink pageLink) {
return DaoUtil.toPageData(
lcEventRepository.findEvents(tenantId, entityId, pageLink.getStartTime(), pageLink.getEndTime(), DaoUtil.toPageable(pageLink)));
}
private PageData<StatisticsEvent> findStatsEventsWithoutFilter(UUID tenantId, UUID entityId, TimePageLink pageLink) {
return DaoUtil.toPageData(
statsEventRepository.findEventsWithoutFilter(tenantId, entityId, pageLink.getStartTime(), pageLink.getEndTime(), DaoUtil.toPageable(pageLink)));
}
private PageData<ErrorEvent> findErrorEventsWithoutFilter(UUID tenantId, UUID entityId, TimePageLink pageLink) {
return DaoUtil.toPageData(
errorEventRepository.findEvents(tenantId, entityId, pageLink.getStartTime(), pageLink.getEndTime(), DaoUtil.toPageable(pageLink)));
}
@Override
public PageData<? extends Event> findEventByFilter(UUID tenantId, UUID entityId, EventFilter eventFilter, TimePageLink pageLink) {
if (eventFilter.hasFilterForJsonBody()) {
if (eventFilter.isNotEmpty()) {
switch (eventFilter.getEventType()) {
case DEBUG_RULE_NODE:
return findEventByFilter(tenantId, entityId, (RuleNodeDebugEventFilter) eventFilter, pageLink);
case DEBUG_RULE_CHAIN:
return findEventByFilter(tenantId, entityId, (DebugEvent) eventFilter, pageLink);
return findEventByFilter(tenantId, entityId, (RuleChainDebugEventFilter) eventFilter, pageLink);
case LC_EVENT:
return findEventByFilter(tenantId, entityId, (LifeCycleEventFilter) eventFilter, pageLink);
case ERROR:
@ -256,27 +225,41 @@ public class JpaBaseEventDao implements EventDao {
}
}
private PageData<EventInfo> findEventByFilter(UUID tenantId, EntityId entityId, DebugEvent eventFilter, TimePageLink pageLink) {
return null;
// return DaoUtil.toPageData(
// eventRepository.findDebugRuleNodeEvents(
// tenantId,
// entityId.getId(),
// entityId.getEntityType().name(),
// eventFilter.getEventType().name(),
// notNull(pageLink.getStartTime()),
// notNull(pageLink.getEndTime()),
// eventFilter.getMsgDirectionType(),
// eventFilter.getServer(),
// eventFilter.getEntityName(),
// eventFilter.getRelationType(),
// eventFilter.getEntityId(),
// eventFilter.getMsgType(),
// eventFilter.isError(),
// eventFilter.getErrorStr(),
// eventFilter.getDataSearch(),
// eventFilter.getMetadataSearch(),
// DaoUtil.toPageable(pageLink)));
private PageData<? extends Event> findEventByFilter(UUID tenantId, UUID entityId, RuleChainDebugEventFilter eventFilter, TimePageLink pageLink) {
return DaoUtil.toPageData(
ruleChainDebugEventRepository.findEvents(
tenantId,
entityId,
pageLink.getStartTime(),
pageLink.getEndTime(),
eventFilter.getServer(),
eventFilter.getMessage(),
eventFilter.isError(),
eventFilter.getErrorStr(),
DaoUtil.toPageable(pageLink)));
}
private PageData<? extends Event> findEventByFilter(UUID tenantId, UUID entityId, RuleNodeDebugEventFilter eventFilter, TimePageLink pageLink) {
parseUUID(eventFilter.getEntityId(), "Entity Id");
parseUUID(eventFilter.getMsgId(), "Message Id");
return DaoUtil.toPageData(
ruleNodeDebugEventRepository.findEvents(
tenantId,
entityId,
pageLink.getStartTime(),
pageLink.getEndTime(),
eventFilter.getServer(),
eventFilter.getMsgDirectionType(),
eventFilter.getEntityId(),
eventFilter.getEntityType(),
eventFilter.getMsgId(),
eventFilter.getMsgType(),
eventFilter.getRelationType(),
eventFilter.getDataSearch(),
eventFilter.getMetadataSearch(),
eventFilter.isError(),
eventFilter.getErrorStr(),
DaoUtil.toPageable(pageLink)));
}
private PageData<? extends Event> findEventByFilter(UUID tenantId, UUID entityId, ErrorEventFilter eventFilter, TimePageLink pageLink) {
@ -311,32 +294,23 @@ public class JpaBaseEventDao implements EventDao {
);
}
private PageData<EventInfo> findEventByFilter(UUID tenantId, EntityId entityId, StatisticsEventFilter eventFilter, TimePageLink pageLink) {
return null;
// return DaoUtil.toPageData(
// eventRepository.findStatisticsEvents(
// tenantId,
// entityId.getId(),
// entityId.getEntityType().name(),
// notNull(pageLink.getStartTime()),
// notNull(pageLink.getEndTime()),
// eventFilter.getServer(),
// notNull(eventFilter.getMessagesProcessed()),
// notNull(eventFilter.getErrorsOccurred()),
// DaoUtil.toPageable(pageLink))
// );
private PageData<? extends Event> findEventByFilter(UUID tenantId, UUID entityId, StatisticsEventFilter eventFilter, TimePageLink pageLink) {
return DaoUtil.toPageData(
statsEventRepository.findEvents(
tenantId,
entityId,
pageLink.getStartTime(),
pageLink.getEndTime(),
eventFilter.getServer(),
eventFilter.getMessagesProcessed(),
eventFilter.getErrorsOccurred(),
DaoUtil.toPageable(pageLink))
);
}
@Override
public List<EventInfo> findLatestEvents(UUID tenantId, UUID entityId, EventType eventType, int limit) {
return null;
// List<EventEntity> latest = eventRepository.findLatestByTenantIdAndEntityTypeAndEntityIdAndEventType(
// tenantId,
// entityId.getEntityType(),
// entityId.getId(),
// eventType,
// PageRequest.of(0, limit));
// return DaoUtil.convertDataList(latest);
public List<? extends Event> findLatestEvents(UUID tenantId, UUID entityId, EventType eventType, int limit) {
return DaoUtil.convertDataList(getEventRepository(eventType).findLatestEvents(tenantId, entityId, limit));
}
@Override
@ -345,12 +319,23 @@ public class JpaBaseEventDao implements EventDao {
eventCleanupRepository.cleanupEvents(regularEventStartTs, regularEventEndTs, debugEventStartTs, debugEventEndTs);
}
private long notNull(Long value) {
return value != null ? value : 0;
private void parseUUID(String src, String paramName) {
if (!StringUtils.isEmpty(src)) {
try {
UUID.fromString(src);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("Failed to convert " + paramName + " to UUID!");
}
}
}
private int notNull(Integer value) {
return value != null ? value : 0;
private EventRepository<? extends EventEntity<?>, ?> getEventRepository(EventType eventType) {
var repository = repositories.get(eventType);
if (repository == null) {
throw new RuntimeException("Event type: " + eventType + " is not supported!");
}
return repository;
}
}

12
dao/src/main/java/org/thingsboard/server/dao/sql/event/LifecycleEventRepository.java

@ -20,14 +20,18 @@ import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.thingsboard.server.common.data.event.LifecycleEvent;
import org.thingsboard.server.dao.model.sql.LifecycleEventEntity;
import java.util.List;
import java.util.UUID;
/**
* Created by Valerii Sosliuk on 5/3/2017.
*/
public interface LifecycleEventRepository extends JpaRepository<LifecycleEventEntity, UUID> {
public interface LifecycleEventRepository extends EventRepository<LifecycleEventEntity, LifecycleEvent>, JpaRepository<LifecycleEventEntity, UUID> {
@Override
@Query("SELECT e FROM LifecycleEventEntity e WHERE e.tenantId = :tenantId AND e.entityId = :entityId ORDER BY e.ts DESC")
List<LifecycleEventEntity> findLatestEvents(UUID tenantId, UUID entityId, int limit);
@Query("SELECT e FROM LifecycleEventEntity e WHERE " +
"e.tenantId = :tenantId " +

82
dao/src/main/java/org/thingsboard/server/dao/sql/event/RuleChainDebugEventRepository.java

@ -0,0 +1,82 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.sql.event;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.thingsboard.server.common.data.event.RuleChainDebugEvent;
import org.thingsboard.server.common.data.event.RuleNodeDebugEvent;
import org.thingsboard.server.dao.model.sql.RuleChainDebugEventEntity;
import org.thingsboard.server.dao.model.sql.RuleNodeDebugEventEntity;
import java.util.List;
import java.util.UUID;
public interface RuleChainDebugEventRepository extends EventRepository<RuleChainDebugEventEntity, RuleChainDebugEvent>, JpaRepository<RuleChainDebugEventEntity, UUID> {
@Override
@Query("SELECT e FROM RuleChainDebugEventEntity e WHERE e.tenantId = :tenantId AND e.entityId = :entityId ORDER BY e.ts DESC")
List<RuleChainDebugEventEntity> findLatestEvents(UUID tenantId, UUID entityId, int limit);
@Override
@Query("SELECT e FROM RuleChainDebugEventEntity e WHERE " +
"e.tenantId = :tenantId " +
"AND e.entityId = :entityId " +
"AND (:startTime IS NULL OR e.ts >= :startTime) " +
"AND (:endTime IS NULL OR e.ts <= :endTime)"
)
Page<RuleChainDebugEventEntity> findEvents(@Param("tenantId") UUID tenantId,
@Param("entityId") UUID entityId,
@Param("startTime") Long startTime,
@Param("endTime") Long endTime,
Pageable pageable);
@Query(nativeQuery = true,
value = "SELECT * FROM rule_chain_debug_event e WHERE " +
"e.tenant_id = :tenantId " +
"AND e.entity_id = :entityId " +
"AND (:startTime IS NULL OR e.ts >= :startTime) " +
"AND (:endTime IS NULL OR e.ts <= :endTime) " +
"AND (:serviceId IS NULL OR e.service_id ILIKE concat('%', :serviceId, '%')) " +
"AND (:message IS NULL OR e.e_message ILIKE concat('%', :message, '%')) " +
"AND ((:isError = FALSE) OR e.e_error IS NOT NULL) " +
"AND (:error IS NULL OR e.e_error ILIKE concat('%', :error, '%'))"
,
countQuery = "SELECT count(*) FROM rule_chain_debug_event e WHERE " +
"e.tenant_id = :tenantId " +
"AND e.entity_id = :entityId " +
"AND (:startTime IS NULL OR e.ts >= :startTime) " +
"AND (:endTime IS NULL OR e.ts <= :endTime) " +
"AND (:serviceId IS NULL OR e.service_id ILIKE concat('%', :serviceId, '%')) " +
"AND (:message IS NULL OR e.e_message ILIKE concat('%', :message, '%')) " +
"AND ((:isError = FALSE) OR e.e_error IS NOT NULL) " +
"AND (:error IS NULL OR e.e_error ILIKE concat('%', :error, '%'))"
)
Page<RuleChainDebugEventEntity> findEvents(@Param("tenantId") UUID tenantId,
@Param("entityId") UUID entityId,
@Param("startTime") Long startTime,
@Param("endTime") Long endTime,
@Param("serviceId") String server,
@Param("message") String message,
@Param("isError") boolean isError,
@Param("error") String error,
Pageable pageable);
}

103
dao/src/main/java/org/thingsboard/server/dao/sql/event/RuleNodeDebugEventRepository.java

@ -0,0 +1,103 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.sql.event;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.thingsboard.server.common.data.event.ErrorEvent;
import org.thingsboard.server.common.data.event.RuleNodeDebugEvent;
import org.thingsboard.server.dao.model.sql.ErrorEventEntity;
import org.thingsboard.server.dao.model.sql.RuleNodeDebugEventEntity;
import java.util.List;
import java.util.UUID;
public interface RuleNodeDebugEventRepository extends EventRepository<RuleNodeDebugEventEntity, RuleNodeDebugEvent>, JpaRepository<RuleNodeDebugEventEntity, UUID> {
@Override
@Query("SELECT e FROM RuleNodeDebugEventEntity e WHERE e.tenantId = :tenantId AND e.entityId = :entityId ORDER BY e.ts DESC")
List<RuleNodeDebugEventEntity> findLatestEvents(UUID tenantId, UUID entityId, int limit);
@Override
@Query("SELECT e FROM RuleNodeDebugEventEntity e WHERE " +
"e.tenantId = :tenantId " +
"AND e.entityId = :entityId " +
"AND (:startTime IS NULL OR e.ts >= :startTime) " +
"AND (:endTime IS NULL OR e.ts <= :endTime)"
)
Page<RuleNodeDebugEventEntity> findEvents(@Param("tenantId") UUID tenantId,
@Param("entityId") UUID entityId,
@Param("startTime") Long startTime,
@Param("endTime") Long endTime,
Pageable pageable);
@Query(nativeQuery = true,
value = "SELECT * FROM rule_node_debug_event e WHERE " +
"e.tenant_id = :tenantId " +
"AND e.entity_id = :entityId " +
"AND (:startTime IS NULL OR e.ts >= :startTime) " +
"AND (:endTime IS NULL OR e.ts <= :endTime) " +
"AND (:serviceId IS NULL OR e.service_id ILIKE concat('%', :serviceId, '%')) " +
"AND (:eventType IS NULL OR e.e_type ILIKE concat('%', :eventType, '%')) " +
"AND (:eventEntityId IS NULL OR e.e_entity_id = uuid(:eventEntityId)) " +
"AND (:eventEntityType IS NULL OR e.e_entity_type ILIKE concat('%', :eventEntityType, '%')) " +
"AND (:msgId IS NULL OR e.e_msg_id = uuid(:msgId)) " +
"AND (:msgType IS NULL OR e.e_msg_type ILIKE concat('%', :msgType, '%')) " +
"AND (:relationType IS NULL OR e.e_relation_type ILIKE concat('%', :relationType, '%')) " +
"AND (:data IS NULL OR e.e_data ILIKE concat('%', :data, '%')) " +
"AND (:metadata IS NULL OR e.e_metadata ILIKE concat('%', :metadata, '%')) " +
"AND ((:isError = FALSE) OR e.e_error IS NOT NULL) " +
"AND (:error IS NULL OR e.e_error ILIKE concat('%', :error, '%'))"
,
countQuery = "SELECT count(*) FROM rule_node_debug_event e WHERE " +
"e.tenant_id = :tenantId " +
"AND e.entity_id = :entityId " +
"AND (:startTime IS NULL OR e.ts >= :startTime) " +
"AND (:endTime IS NULL OR e.ts <= :endTime) " +
"AND (:serviceId IS NULL OR e.service_id ILIKE concat('%', :serviceId, '%')) " +
"AND (:eventType IS NULL OR e.e_type ILIKE concat('%', :eventType, '%')) " +
"AND (:eventEntityId IS NULL OR e.e_entity_id = uuid(:eventEntityId)) " +
"AND (:eventEntityType IS NULL OR e.e_entity_type ILIKE concat('%', :eventEntityType, '%')) " +
"AND (:msgId IS NULL OR e.e_msg_id = uuid(:msgId)) " +
"AND (:msgType IS NULL OR e.e_msg_type ILIKE concat('%', :msgType, '%')) " +
"AND (:relationType IS NULL OR e.e_relation_type ILIKE concat('%', :relationType, '%')) " +
"AND (:data IS NULL OR e.e_data ILIKE concat('%', :data, '%')) " +
"AND (:metadata IS NULL OR e.e_metadata ILIKE concat('%', :metadata, '%')) " +
"AND ((:isError = FALSE) OR e.e_error IS NOT NULL) " +
"AND (:error IS NULL OR e.e_error ILIKE concat('%', :error, '%'))"
)
Page<RuleNodeDebugEventEntity> findEvents(@Param("tenantId") UUID tenantId,
@Param("entityId") UUID entityId,
@Param("startTime") Long startTime,
@Param("endTime") Long endTime,
@Param("serviceId") String server,
@Param("eventType") String type,
@Param("eventEntityId") String eventEntityId,
@Param("eventEntityType") String eventEntityType,
@Param("msgId") String eventMsgId,
@Param("msgType") String eventMsgType,
@Param("relationType") String relationType,
@Param("data") String data,
@Param("metadata") String metadata,
@Param("isError") boolean isError,
@Param("error") String error,
Pageable pageable);
}

49
dao/src/main/java/org/thingsboard/server/dao/sql/event/StatisticsEventRepository.java

@ -21,15 +21,16 @@ import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.thingsboard.server.common.data.event.StatisticsEvent;
import org.thingsboard.server.dao.model.sql.LifecycleEventEntity;
import org.thingsboard.server.dao.model.sql.StatisticsEventEntity;
import java.util.List;
import java.util.UUID;
/**
* Created by Valerii Sosliuk on 5/3/2017.
*/
public interface StatisticsEventRepository extends JpaRepository<StatisticsEventEntity, UUID> {
public interface StatisticsEventRepository extends EventRepository<StatisticsEventEntity, StatisticsEvent>, JpaRepository<StatisticsEventEntity, UUID> {
@Override
@Query("SELECT e FROM LifecycleEventEntity e WHERE e.tenantId = :tenantId AND e.entityId = :entityId ORDER BY e.ts DESC")
List<StatisticsEventEntity> findLatestEvents(UUID tenantId, UUID entityId, int limit);
@Query("SELECT e FROM StatisticsEventEntity e WHERE " +
"e.tenantId = :tenantId " +
@ -37,10 +38,38 @@ public interface StatisticsEventRepository extends JpaRepository<StatisticsEvent
"AND (:startTime IS NULL OR e.ts >= :startTime) " +
"AND (:endTime IS NULL OR e.ts <= :endTime)"
)
Page<StatisticsEventEntity> findEventsWithoutFilter(@Param("tenantId") UUID tenantId,
@Param("entityId") UUID entityId,
@Param("startTime") Long startTime,
@Param("endTime") Long endTime,
Pageable pageable);
Page<StatisticsEventEntity> findEvents(@Param("tenantId") UUID tenantId,
@Param("entityId") UUID entityId,
@Param("startTime") Long startTime,
@Param("endTime") Long endTime,
Pageable pageable);
@Query(nativeQuery = true,
value = "SELECT * FROM stats_event e WHERE " +
"e.tenant_id = :tenantId " +
"AND e.entity_id = :entityId " +
"AND (:startTime IS NULL OR e.ts >= :startTime) " +
"AND (:endTime IS NULL OR e.ts <= :endTime) " +
"AND (:serviceId IS NULL OR e.service_id ILIKE concat('%', :serviceId, '%')) " +
"AND (:messagesProcessed IS NULL OR e.e_messages_processed >= :messagesProcessed) " +
"AND (:errorsOccurred IS NULL OR e.e_errors_occurred >= :errorsOccurred)"
,
countQuery = "SELECT count(*) FROM stats_event e WHERE " +
"e.tenant_id = :tenantId " +
"AND e.entity_id = :entityId " +
"AND (:startTime IS NULL OR e.ts >= :startTime) " +
"AND (:endTime IS NULL OR e.ts <= :endTime) " +
"AND (:serviceId IS NULL OR e.service_id ILIKE concat('%', :serviceId, '%')) " +
"AND (:messagesProcessed IS NULL OR e.e_messages_processed >= :messagesProcessed) " +
"AND (:errorsOccurred IS NULL OR e.e_errors_occurred >= :errorsOccurred)"
)
Page<StatisticsEventEntity> findEvents(@Param("tenantId") UUID tenantId,
@Param("entityId") UUID entityId,
@Param("startTime") Long startTime,
@Param("endTime") Long endTime,
@Param("serviceId") String server,
@Param("messagesProcessed") Integer messagesProcessed,
@Param("errorsOccurred") Integer errorsOccurred,
Pageable pageable);
}

10
dao/src/main/resources/sql/schema-entities-idx-psql-addon.sql

@ -22,17 +22,17 @@
-- That why we need to define DESC index explicitly as (ts DESC NULLS LAST)
CREATE INDEX IF NOT EXISTS idx_rule_node_debug_event_main
ON rule_node_debug_event (tenant_id ASC, entity_id ASC, ts DESC) WITH (FILLFACTOR=95);
ON rule_node_debug_event (tenant_id ASC, entity_id ASC, ts DESC NULLS LAST) WITH (FILLFACTOR=95);
CREATE INDEX IF NOT EXISTS idx_rule_chain_debug_event_main
ON rule_chain_debug_event (tenant_id ASC, entity_id ASC, ts DESC) WITH (FILLFACTOR=95);
ON rule_chain_debug_event (tenant_id ASC, entity_id ASC, ts DESC NULLS LAST) WITH (FILLFACTOR=95);
CREATE INDEX IF NOT EXISTS idx_stats_event_main
ON stats_event (tenant_id ASC, entity_id ASC, ts DESC) WITH (FILLFACTOR=95);
ON stats_event (tenant_id ASC, entity_id ASC, ts DESC NULLS LAST) WITH (FILLFACTOR=95);
CREATE INDEX IF NOT EXISTS idx_lc_event_main
ON lc_event (tenant_id ASC, entity_id ASC, ts DESC) WITH (FILLFACTOR=95);
ON lc_event (tenant_id ASC, entity_id ASC, ts DESC NULLS LAST) WITH (FILLFACTOR=95);
CREATE INDEX IF NOT EXISTS idx_error_event_main
ON error_event (tenant_id ASC, entity_id ASC, ts DESC) WITH (FILLFACTOR=95);
ON error_event (tenant_id ASC, entity_id ASC, ts DESC NULLS LAST) WITH (FILLFACTOR=95);

6
dao/src/main/resources/sql/schema-entities.sql

@ -336,9 +336,9 @@ CREATE TABLE IF NOT EXISTS rule_node_debug_event (
e_msg_type varchar,
e_data_type varchar,
e_relation_type varchar,
e_data varchar NOT NULL,
e_metadata varchar NOT NULL,
e_error varchar NOT NULL
e_data varchar,
e_metadata varchar,
e_error varchar
) PARTITION BY RANGE (ts);
CREATE TABLE IF NOT EXISTS rule_chain_debug_event (

4
ui-ngx/src/app/modules/home/components/event/event-table-config.ts

@ -234,8 +234,8 @@ export class EventTableConfig extends EntityTableConfig<Event, TimePageLink> {
}), false, key => ({
padding: '0 12px 0 0'
})),
new EntityTableColumn<Event>('entityName', 'event.entity-type', '100px',
(entity) => entity.body.entityName, entity => ({
new EntityTableColumn<Event>('entityType', 'event.entity-type', '100px',
(entity) => entity.body.entityType, entity => ({
padding: '0 12px 0 0',
}), false, key => ({
padding: '0 12px 0 0'

2
ui-ngx/src/app/shared/models/event.models.ts

@ -65,7 +65,7 @@ export interface StatsEventBody extends BaseEventBody {
export interface DebugRuleNodeEventBody extends BaseEventBody {
type: string;
entityId: string;
entityName: string;
entityType: string;
msgId: string;
msgType: string;
relationType: string;

Loading…
Cancel
Save