com.sap.cds.feature.dashboard.service.DashboardServiceConfiguration Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cds-feature-dev-dashboard Show documentation
Show all versions of cds-feature-dev-dashboard Show documentation
Development Dashboard for CDS Services Java
/**************************************************************************
* (C) 2019-2021 SAP SE or an SAP affiliate company. All rights reserved. *
**************************************************************************/
package com.sap.cds.feature.dashboard.service;
import java.util.Collections;
import java.util.LinkedList;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import com.sap.cds.feature.dashboard.connectivity.InfoEvent;
import com.sap.cds.feature.dashboard.info.InfoCollector;
import com.sap.cds.feature.dashboard.info.Path;
import com.sap.cds.feature.dashboard.info.collectors.CdsInfoCollector;
import com.sap.cds.feature.dashboard.info.collectors.ClientInfoCollector;
import com.sap.cds.feature.dashboard.info.collectors.LogCollector;
import com.sap.cds.feature.dashboard.info.collectors.MessagingInfoCollector;
import com.sap.cds.feature.dashboard.info.collectors.MultitenancyInfoCollector;
import com.sap.cds.feature.dashboard.info.collectors.OutboxInfoCollector;
import com.sap.cds.feature.dashboard.info.collectors.PersistenceCollector;
import com.sap.cds.feature.dashboard.info.collectors.SystemInfoCollector;
import com.sap.cds.services.application.ApplicationLifecycleService;
import com.sap.cds.services.impl.messaging.composite.MessagingCompositeService;
import com.sap.cds.services.runtime.CdsRuntimeConfiguration;
import com.sap.cds.services.runtime.CdsRuntimeConfigurer;
public class DashboardServiceConfiguration implements CdsRuntimeConfiguration {
private DashboardService dashboardService;
private int totalEventsCount;
private AtomicInteger eventsSample = new AtomicInteger();
private SizeLimitedQueue queue = new SizeLimitedQueue(120);
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private boolean schedulerInitialized;
@Override
public int order() {
return Integer.MAX_VALUE;
}
@Override
public void services(CdsRuntimeConfigurer configurer) {
if (configurer.getCdsRuntime().getEnvironment().getCdsProperties().getIndexPage().isEnabled()) {
dashboardService = new DashboardServiceImpl();
configurer.service(dashboardService);
}
}
@Override
public void eventHandlers(CdsRuntimeConfigurer configurer) {
if (dashboardService != null) {
configurer.eventHandler(new ClientInfoCollector(configurer.getCdsRuntime(), dashboardService));
configurer.eventHandler(new SystemInfoCollector(configurer.getCdsRuntime(), dashboardService));
configurer.eventHandler(new MultitenancyInfoCollector(configurer.getCdsRuntime(), dashboardService));
configurer.eventHandler(new MessagingInfoCollector(configurer.getCdsRuntime(), dashboardService));
configurer.eventHandler(new OutboxInfoCollector(configurer.getCdsRuntime(), dashboardService));
configurer.eventHandler(new PersistenceCollector(configurer.getCdsRuntime(), dashboardService));
configurer.eventHandler(new CdsInfoCollector(configurer.getCdsRuntime(), dashboardService));
configurer.eventHandler(new LogCollector(configurer.getCdsRuntime(), dashboardService));
configurer.getCdsRuntime().getServiceCatalog().getServices().forEach(service -> {
// we don't want to trace dashboard events and also to force messaging composite configuration for '*' event
if (!service.getName().equals(DashboardService.DEFAULT_NAME) &&
!service.getName().equals(MessagingCompositeService.COMPOSITE_NAME)) {
service.after("*", null, ctx -> {
// trace only events produced outside dashboard context
if (!InfoCollector.isInDashboardContext()) {
totalEventsCount++;
eventsSample.incrementAndGet();
dashboardService.emit(PersistenceCollector.createInfo(ctx, Path.TRACES_EVENTS));
dashboardService.emit(createTotalEventsCount());
}
});
}
});
((DashboardServiceImpl) dashboardService).after(ClientInfoCollector.COMMAND_ATTACHED, null, ctx -> {
dashboardService.emit(createEventsSeries());
synchronized (scheduler) {
if (!schedulerInitialized) {
ScheduledFuture> sampler = scheduler.scheduleAtFixedRate(() -> {
int val = eventsSample.getAndSet(0);
queue.add(val);
dashboardService.emit(createEventSampel(val));
}, 0, 3, TimeUnit.SECONDS);
schedulerInitialized = true;
// we need to stop the sampler on shutdown as we could potentially run in a relaunch scenario (watch)
configurer.getCdsRuntime().getServiceCatalog()
.getService(ApplicationLifecycleService.class, ApplicationLifecycleService.DEFAULT_NAME)
.on(ApplicationLifecycleService.EVENT_APPLICATION_STOPPED, null, context -> {
if (sampler != null) {
sampler.cancel(true);
}
});
}
}
});
}
}
public InfoEvent createTotalEventsCount() {
InfoEvent event = InfoEvent.create(Path.SYSTEM);
event.getData().put("total_events_count", totalEventsCount);
return event;
}
public InfoEvent createEventsSeries() {
InfoEvent event = InfoEvent.create(Path.SYSTEM);
event.getData().put("event_series", queue.toArray());
return event;
}
public InfoEvent createEventSampel(int value) {
InfoEvent event = InfoEvent.create(Path.SYSTEM);
event.getData().put("events_sampel", Collections.singletonMap("value", value));
return event;
}
public static class SizeLimitedQueue extends LinkedList {
private static final long serialVersionUID = 1L;
private int queueSize;
public SizeLimitedQueue(int queueSize) {
this.queueSize = queueSize;
for (int i = 0; i < queueSize; i++) {
add(0);
}
}
@Override
public boolean add(Integer o) {
while (this.size() == queueSize) {
super.remove();
}
super.add(o);
return true;
}
}
}