Skip to content
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

License metrics #82

Merged
merged 10 commits into from
Apr 16, 2021
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ Version template:
# Alfred Telemetry Changelog
## [0.5.1] - UNRELEASED

### Added
* Alfresco license metrics [#82]

[#82]: https://github.com/xenit-eu/alfred-telemetry/pull/82

## [0.5.0] - 2021-03-22

### Added
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,11 @@
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.service.cmr.admin.RepoAdminService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nonnull;

public class AlfrescoStatusMetrics implements MeterBinder {

private static final Logger LOGGER = LoggerFactory.getLogger(AlfrescoStatusMetrics.class);
private static final String STATUS_PREFIX = "alfresco.status";

private RepoAdminService repoAdminService;
Expand All @@ -27,7 +24,6 @@ public AlfrescoStatusMetrics(RepoAdminService repoAdminService,

@Override
public void bindTo(@Nonnull MeterRegistry meterRegistry) {
LOGGER.info("Registering Alfresco Status metrics");
Gauge.builder(STATUS_PREFIX + ".readonly", repoAdminService, this::getReadOnly)
.description("Metric about Alfresco being in read-only mode")
.register(meterRegistry);
Expand All @@ -42,10 +38,6 @@ private double getReadOnly(RepoAdminService repoAdminService) {
isReadOnly[0] = repoAdminService.getUsage().isReadOnly()),
true);

if (isReadOnly[0]) {
return 1d;
} else {
return 0d;
}
return (isReadOnly[0] ? 1d : 0d);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package eu.xenit.alfred.telemetry.binder;

import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.binder.MeterBinder;
import org.alfresco.service.descriptor.Descriptor;
import org.alfresco.service.descriptor.DescriptorService;
import org.alfresco.service.license.LicenseDescriptor;
import org.alfresco.service.license.LicenseService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import javax.annotation.Nonnull;

public class LicenseMetrics implements MeterBinder, ApplicationContextAware {

private static final Logger logger = LoggerFactory.getLogger(LicenseMetrics.class);

private static final String METRIC_NAME_LICENSE = "license";

private ApplicationContext ctx;
private DescriptorService descriptorService;

public LicenseMetrics(DescriptorService descriptorService) {
this.descriptorService = descriptorService;
}

@Override
public void bindTo(@Nonnull MeterRegistry registry) {
// do not do anything for Community
Descriptor serverDescriptor = descriptorService.getServerDescriptor();
if(!"Enterprise".equals(serverDescriptor.getEdition())) {
logger.info("Edition={}, license metrics are not available", serverDescriptor.getEdition());
anghelutar marked this conversation as resolved.
Show resolved Hide resolved
return;
}

Gauge.builder(METRIC_NAME_LICENSE + ".valid", ctx, LicenseMetrics::getValid)
.description("Whether the license is still valid")
.register(registry);

Gauge.builder(METRIC_NAME_LICENSE + ".remainingDays", descriptorService, LicenseMetrics::getRemainingDays)
.description("Remaining days")
.register(registry);
Gauge.builder(METRIC_NAME_LICENSE + ".maxDocs", descriptorService, LicenseMetrics::getMaxDocs)
.description("Max docs")
.register(registry);
Gauge.builder(METRIC_NAME_LICENSE + ".maxUsers", descriptorService, LicenseMetrics::getMaxUsers)
vierbergenlars marked this conversation as resolved.
Show resolved Hide resolved
.description("Max users")
.register(registry);
Gauge.builder(METRIC_NAME_LICENSE + ".isClusterEnabled", descriptorService, LicenseMetrics::isClusterEnabled)
anghelutar marked this conversation as resolved.
Show resolved Hide resolved
.description("Clustering enabled")
.register(registry);
Gauge.builder(METRIC_NAME_LICENSE + ".isCryptodocEnabled", descriptorService, LicenseMetrics::isCryptodocEnabled)
.description("Encription enabled")
.register(registry);
Gauge.builder(METRIC_NAME_LICENSE + ".isHeartbeatDisabled", descriptorService, LicenseMetrics::isHeartbeatDisabled)
anghelutar marked this conversation as resolved.
Show resolved Hide resolved
.description("Heartbeat disabled")
.register(registry);
}


private static double getValid(final ApplicationContext ctx) {
LicenseService licenseService = ctx.getBeansOfType(LicenseService.class, false, false).get("licenseService");
if(licenseService!=null)
return (licenseService.isLicenseValid() ? 1 : 0);
return -1;
}

private static int getRemainingDays(final DescriptorService descriptorService) {
LicenseDescriptor licenseDescriptor = descriptorService.getLicenseDescriptor();
if(licenseDescriptor!=null && licenseDescriptor.getRemainingDays()!=null)
return licenseDescriptor.getRemainingDays();
return -1;
}

private static long getMaxDocs(final DescriptorService descriptorService) {
LicenseDescriptor licenseDescriptor = descriptorService.getLicenseDescriptor();
if(licenseDescriptor!=null && licenseDescriptor.getMaxDocs()!=null)
return licenseDescriptor.getMaxDocs();
return -1L;
}

private static long getMaxUsers(final DescriptorService descriptorService) {
LicenseDescriptor licenseDescriptor = descriptorService.getLicenseDescriptor();
if(licenseDescriptor!=null && licenseDescriptor.getMaxUsers()!=null)
return licenseDescriptor.getMaxUsers();
return -1L;
}

private static double isClusterEnabled(final DescriptorService descriptorService) {
LicenseDescriptor licenseDescriptor = descriptorService.getLicenseDescriptor();
if(licenseDescriptor!=null)
return (licenseDescriptor.isClusterEnabled()?1:0);
return -1;
}

private static double isCryptodocEnabled(final DescriptorService descriptorService) {
LicenseDescriptor licenseDescriptor = descriptorService.getLicenseDescriptor();
if(licenseDescriptor!=null)
anghelutar marked this conversation as resolved.
Show resolved Hide resolved
return (licenseDescriptor.isCryptodocEnabled()?1:0);
return -1;
}

private static double isHeartbeatDisabled(final DescriptorService descriptorService) {
LicenseDescriptor licenseDescriptor = descriptorService.getLicenseDescriptor();
if(licenseDescriptor!=null)
return (licenseDescriptor.isHeartBeatDisabled()?1:0);
return -1;
}

@Override
public void setApplicationContext(@Nonnull ApplicationContext applicationContext) throws BeansException {
this.ctx = applicationContext;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ alfred.telemetry.binder.cache.enabled=false
# Alfresco status
alfred.telemetry.binder.alfresco-status.enabled=true

# Alfresco license - will output nothing for community
alfred.telemetry.binder.license.enabled=true

# Care4Alf support - default configuration
## 1. Care4Alf metrics global switch - disabled by default
alfred.telemetry.binder.care4alf.enabled=false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<beans>

<bean id="alfred-telemetry.MeterBinderRegistrar"
class="eu.xenit.alfred.telemetry.binder.MeterBinderRegistrar">
class="eu.xenit.alfred.telemetry.binder.MeterBinderRegistrar">
<constructor-arg ref="meterRegistry"/>
<property name="properties" ref="global-properties"/>
<property name="enabled" value="${alfred.telemetry.binder.enabled}"/>
Expand All @@ -14,7 +14,7 @@
</bean>

<bean id="alfred-telemetry.Care4AlfMeterBinderRegistrar"
class="eu.xenit.alfred.telemetry.binder.care4alf.Care4AlfMeterBinderRegistrar">
class="eu.xenit.alfred.telemetry.binder.care4alf.Care4AlfMeterBinderRegistrar">
<constructor-arg ref="meterRegistry"/>
<property name="properties" ref="global-properties"/>
<property name="enabled" value="${alfred.telemetry.binder.care4alf.enabled}"/>
Expand All @@ -39,6 +39,10 @@
<constructor-arg ref="DescriptorService"/>
</bean>

<bean class="eu.xenit.alfred.telemetry.binder.LicenseMetrics">
<constructor-arg ref="DescriptorService"/>
</bean>

<bean class="eu.xenit.alfred.telemetry.binder.DataSourceMetrics">
<constructor-arg ref="dataSource"/>
</bean>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package eu.xenit.alfred.telemetry.binder;

import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import org.alfresco.service.descriptor.Descriptor;
import org.alfresco.service.descriptor.DescriptorService;
import org.alfresco.service.license.LicenseDescriptor;
import org.alfresco.service.license.LicenseService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;

import java.util.Collections;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertFalse;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class LicenseMetricsTest {

private DescriptorService descriptorService;
private LicenseMetrics licenseMetrics;
private MeterRegistry meterRegistry;
private ApplicationContext applicationContext;
private LicenseService licenseService;
private Descriptor serverDescriptor;
private LicenseDescriptor licenseDescriptor;

@BeforeEach
void setup() {
licenseService = mock(LicenseService.class);
applicationContext = mock(ApplicationContext.class);
descriptorService = mock(DescriptorService.class);
serverDescriptor = mock(Descriptor.class);
licenseDescriptor = mock(LicenseDescriptor.class);

meterRegistry = new SimpleMeterRegistry();
licenseMetrics = new LicenseMetrics(descriptorService);
licenseMetrics.setApplicationContext(applicationContext);

when(descriptorService.getServerDescriptor()).thenReturn(serverDescriptor);
when(descriptorService.getLicenseDescriptor()).thenReturn(licenseDescriptor);
when(applicationContext.getBeansOfType(LicenseService.class,false,false)).thenReturn(Collections.singletonMap("licenseService", licenseService));
when(serverDescriptor.getEdition()).thenReturn("Enterprise");
}

@Test
public void testCommunity() {
when(serverDescriptor.getEdition()).thenReturn("Community");
licenseMetrics.bindTo(meterRegistry);
assertFalse(meterRegistry.getMeters().contains("license.valid"));
}

@Test
public void testNoLicenseService() {
when(applicationContext.getBeansOfType(LicenseService.class,false,false)).thenReturn(Collections.singletonMap("licenseService", null));
licenseMetrics.bindTo(meterRegistry);
assertThat(meterRegistry.get("license.valid").gauge().value(),is(-1.0));
}

@Test
public void testNoLicenseDescriptor() {
when(descriptorService.getLicenseDescriptor()).thenReturn(null);
licenseMetrics.bindTo(meterRegistry);
assertThat(meterRegistry.get("license.maxDocs").gauge().value(),is(-1.0));
}

@Test
public void testLicenseMetrics() {
licenseMetrics.bindTo(meterRegistry);

when(licenseService.isLicenseValid()).thenReturn(true);
assertThat(meterRegistry.get("license.valid").gauge().value(),is(1.0));

when(licenseService.isLicenseValid()).thenReturn(false);
assertThat(meterRegistry.get("license.valid").gauge().value(),is(0.0));

when(licenseDescriptor.getMaxDocs()).thenReturn(100L);
assertThat(meterRegistry.get("license.maxDocs").gauge().value(),is(100.0));

when(licenseDescriptor.getMaxDocs()).thenReturn(null);
assertThat(meterRegistry.get("license.maxDocs").gauge().value(),is(-1.0));

when(licenseDescriptor.getMaxUsers()).thenReturn(100L);
assertThat(meterRegistry.get("license.maxUsers").gauge().value(),is(100.0));

when(licenseDescriptor.getMaxUsers()).thenReturn(null);
assertThat(meterRegistry.get("license.maxUsers").gauge().value(),is(-1.0));

when(licenseDescriptor.getRemainingDays()).thenReturn(100);
assertThat(meterRegistry.get("license.remainingDays").gauge().value(),is(100.0));

when(licenseDescriptor.getRemainingDays()).thenReturn(null);
assertThat(meterRegistry.get("license.remainingDays").gauge().value(),is(-1.0));

when(licenseDescriptor.isClusterEnabled()).thenReturn(false);
assertThat(meterRegistry.get("license.isClusterEnabled").gauge().value(),is(0.0));

when(licenseDescriptor.isClusterEnabled()).thenReturn(true);
assertThat(meterRegistry.get("license.isClusterEnabled").gauge().value(),is(1.0));

when(licenseDescriptor.isCryptodocEnabled()).thenReturn(false);
assertThat(meterRegistry.get("license.isCryptodocEnabled").gauge().value(),is(0.0));

when(licenseDescriptor.isCryptodocEnabled()).thenReturn(true);
assertThat(meterRegistry.get("license.isCryptodocEnabled").gauge().value(),is(1.0));

when(licenseDescriptor.isHeartBeatDisabled()).thenReturn(false);
assertThat(meterRegistry.get("license.isHeartbeatDisabled").gauge().value(),is(0.0));

when(licenseDescriptor.isHeartBeatDisabled()).thenReturn(true);
assertThat(meterRegistry.get("license.isHeartbeatDisabled").gauge().value(),is(1.0));
}
}
18 changes: 18 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,24 @@ Metrics provided
| :------------------------------------ | :----------------------- |
| alfresco.status.readonly | |

## License metrics
The license metrics bindings will provide metrics about Alfresco license. Enterprise-only feature.

**Control Property**: `alfred.telemetry.binder.license.enabled`

Metrics provided

| Name | Available tags |
| :------------------------------------ | :----------------------- |
| license.valid | |
| license.maxUsers | |
anghelutar marked this conversation as resolved.
Show resolved Hide resolved
| license.maxDocs | |
| license.remainingDays | |
| license.isClusterEnabled | |
| license.isCryptodocEnabled | |
| license.isHeartbeatDisabled | |



## Alfresco Node metrics

Expand Down
7 changes: 7 additions & 0 deletions integration-tests/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ subprojects {
apply plugin: 'java'

def alfrescoVersion = project.name[-2..-1]
def alfrescoEdition = "Community"
if(project.hasProperty("enterprise")) {
alfrescoEdition = "Enterprise"
}

apply from: "${project.projectDir}/overload.gradle"

description = "Alfresco ${alfrescoVersion} with Alfred Micrometer"
Expand All @@ -51,6 +56,8 @@ subprojects {
doFirst {
dockerCompose.solr.exposeAsSystemProperties(integrationTest)
systemProperty 'solrFlavor', "${solrFlavor}"
systemProperty 'alfrescoEdition', alfrescoEdition

}
}

Expand Down
Loading