Skip to content

Commit

Permalink
Update the naming of metrics to be more consistent with other services.
Browse files Browse the repository at this point in the history
Add a test for the metrics service
Align application.properties and application_test.properties
  • Loading branch information
jacomago committed Jan 23, 2024
1 parent 7c2155b commit 9b84977
Show file tree
Hide file tree
Showing 12 changed files with 338 additions and 156 deletions.
5 changes: 4 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
FROM openjdk:11-jre
WORKDIR /channelfinder
ADD https://repo1.maven.org/maven2/org/phoebus/app-channel-channelfinder/4.7.2/app-channel-channelfinder-4.7.2.jar .
ADD https://repo1.maven.org/maven2/org/phoebus/ChannelFinder/4.7.2/ChannelFinder-4.7.2.jar .

CMD ["java", "-jar", "./ChannelFinder-*.jar", "--spring.config.name=application"]

114 changes: 63 additions & 51 deletions src/main/java/org/phoebus/channelfinder/MetricsService.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,80 +11,92 @@
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;


@Service
@PropertySource(value = "classpath:application.properties")
public class MetricsService {

private static final Logger logger = Logger.getLogger(MetricsService.class.getName());
public static final String CF_TOTAL_CHANNEL_COUNT = "cf.total.channel.count";
public static final String CF_PROPERTY_COUNT = "cf.property.count";
public static final String CF_TAG_COUNT = "cf.tag.count";
public static final String CF_CHANNEL_COUNT = "cf.channel.count";
private static final String METRIC_DESCRIPTION_TOTAL_CHANNEL_COUNT = "Count of all ChannelFinder channels";
private static final String METRIC_DESCRIPTION_PROPERTY_COUNT = "Count of all ChannelFinder properties";
private static final String METRIC_DESCRIPTION_TAG_COUNT = "Count of all ChannelFinder tags";
private static final String METRIC_DESCRIPTION_CHANNEL_COUNT =
"Count of channels with specific property with and specific value";
private final ChannelRepository channelRepository;
private final PropertyRepository propertyRepository;
private final TagRepository tagRepository;
private final MeterRegistry meterRegistry;

MultiGauge channelCounts;

@Value("${metrics.tags}")
private String[] tags;

@Value("#{${metrics.properties:{'pvStatus': 'Active'}}}")
private Map<String, String> properties;

private static final Logger logger = Logger.getLogger(MetricsService.class.getName());
private static final String METRIC_NAME_CHANNEL_COUNT = "cf_channel_count";
private static final String METRIC_NAME_PROPERTIES_COUNT = "cf_properties_count";
private static final String METRIC_NAME_TAGS_COUNT = "cf_tags_count";
private static final String METRIC_NAME_CHANNEL_COUNT_PER_PROPERTY = "cf_channel_count_per_property";
private static final String METRIC_NAME_CHANNEL_COUNT_PER_TAG = "cf_channel_count_per_tag";
private static final String METRIC_DESCRIPTION_CHANNEL_COUNT = "Count of channel finder channels";
private static final String METRIC_DESCRIPTION_PROPERTIES_COUNT = "Count of channel finder properties";
private static final String METRIC_DESCRIPTION_TAGS_COUNT = "Count of channel finder tags";
private static final String METRIC_DESCRIPTION_CHANNEL_COUNT_PER_PROPERTY = "Count of channels with specific property with and specific value";
private static final String METRIC_DESCRIPTION_CHANNEL_COUNT_PER_TAG = "Count of channels with specific tag";
@Value("#{${metrics.properties:{{'pvStatus', 'Active'}, {'pvStatus', 'Inactive'}}}}")
private String[][] properties;

private final ChannelRepository channelRepository;
private final PropertyRepository propertyRepository;
@Autowired
public MetricsService(final ChannelRepository channelRepository, final PropertyRepository propertyRepository, final TagRepository tagRepository, final MeterRegistry meterRegistry) {
public MetricsService(
final ChannelRepository channelRepository,
final PropertyRepository propertyRepository,
final TagRepository tagRepository,
final MeterRegistry meterRegistry) {
this.channelRepository = channelRepository;
this.propertyRepository = propertyRepository;
registerGaugeMetrics(meterRegistry, tagRepository);
this.tagRepository = tagRepository;
this.meterRegistry = meterRegistry;
registerGaugeMetrics();
}

MultiGauge propertyCounts;
MultiGauge tagCounts;

private void registerGaugeMetrics(MeterRegistry meterRegistry, TagRepository tagRepository){
Gauge.builder(METRIC_NAME_CHANNEL_COUNT, () -> channelRepository.count(new LinkedMultiValueMap<>()))
.description(METRIC_DESCRIPTION_CHANNEL_COUNT)
private void registerGaugeMetrics() {
Gauge.builder(CF_TOTAL_CHANNEL_COUNT, () -> channelRepository.count(new LinkedMultiValueMap<>()))
.description(METRIC_DESCRIPTION_TOTAL_CHANNEL_COUNT)
.register(meterRegistry);
Gauge.builder(METRIC_NAME_PROPERTIES_COUNT,
propertyRepository::count)
.description(METRIC_DESCRIPTION_PROPERTIES_COUNT)
Gauge.builder(CF_PROPERTY_COUNT, propertyRepository::count)
.description(METRIC_DESCRIPTION_PROPERTY_COUNT)
.register(meterRegistry);
Gauge.builder(METRIC_NAME_TAGS_COUNT,
tagRepository::count)
.description(METRIC_DESCRIPTION_TAGS_COUNT)
Gauge.builder(CF_TAG_COUNT, tagRepository::count)
.description(METRIC_DESCRIPTION_TAG_COUNT)
.register(meterRegistry);

propertyCounts = MultiGauge.builder(METRIC_NAME_CHANNEL_COUNT_PER_PROPERTY)
.description(METRIC_DESCRIPTION_CHANNEL_COUNT_PER_PROPERTY)
.register(meterRegistry);

tagCounts = MultiGauge.builder(METRIC_NAME_CHANNEL_COUNT_PER_TAG)
.description(METRIC_DESCRIPTION_CHANNEL_COUNT_PER_TAG)
channelCounts = MultiGauge.builder(CF_CHANNEL_COUNT)
.description(METRIC_DESCRIPTION_CHANNEL_COUNT)
.baseUnit("channels")
.register(meterRegistry);

}

@Scheduled(fixedRate = 10000)
@Scheduled(fixedRate = 5000)
public void updateMetrics() {
logger.log(Level.INFO, "Updating metrics");
propertyCounts.register(
properties.entrySet().stream().map(property -> MultiGauge.Row.of(Tags.of(property.getKey(), property.getValue()),
channelRepository.countByProperty(property.getKey(), property.getValue()))).collect(Collectors.toList())
);
tagCounts.register(
Arrays.stream(tags).map(tag -> MultiGauge.Row.of(Tags.of("tag", tag),
channelRepository.countByTag(tag))).collect(Collectors.toList())
);
logger.log(
Level.FINER,
() -> "Updating metrics for properties " + Arrays.deepToString(properties) + " and tags " + Arrays.toString(tags));
ArrayList<MultiGauge.Row<?>> rows = new ArrayList<>();

// Add tags
for (String tag: tags) {
long count = channelRepository.countByTag(tag);
rows.add(MultiGauge.Row.of(Tags.of("tag", tag), count ));
logger.log(
Level.FINER,
() -> "Updating metrics for tag " + tag + " to " + count);
}

// Add properties
for (String[] propertyValue: properties) {
long count = channelRepository.countByProperty(propertyValue[0], propertyValue[1]);
rows.add(MultiGauge.Row.of(Tags.of(propertyValue[0], propertyValue[1]), count));
logger.log(
Level.FINER,
() -> "Updating metrics for property " + propertyValue[0] + ":" + propertyValue[1] + " to " + count);
}

channelCounts.register(rows, true);
}
}
61 changes: 50 additions & 11 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,14 @@ server.ssl.key-alias=cf

security.require-ssl=true

logging.level.org.springframework.web=INFO
spring.http.log-request-details=true

# Enable HTTP/2 support, if the current environment supports it
server.http2.enabled=true

server.compression.enabled=true
# opt in to content types
server.compression.mime-types=application/json,application/xml,text/html,text/xml,text/plain,application/javascript,text/css
# not worth the CPU cycles at some point, probably
server.compression.min-response-size=1024
# Enable HTTP/2 support, if the current environment supports it
server.http2.enabled=true
logging.level.org.springframework.web=INFO

############## LDAP - External ##############
ldap.enabled = false
Expand All @@ -36,6 +33,7 @@ ldap.groups.search.pattern = (memberUid= {1})
############## LDAP - Embedded ##############
embedded_ldap.enabled = false
embedded_ldap.urls = ldap://localhost:8389/dc=cf,dc=local
embedded_ldap.base.dn = dc=cf,dc=local
embedded_ldap.user.dn.pattern = uid={0},ou=People,dc=cf,dc=local
embedded_ldap.groups.search.base = ou=Group,dc=cf,dc=local
embedded_ldap.groups.search.pattern = (memberUid= {1})
Expand All @@ -58,7 +56,7 @@ demo_auth.users = admin,user
demo_auth.pwds = adminPass,userPass
demo_auth.roles = ADMIN,USER

############## Role --> group Mapping ##############
############## Group-->Role Mapping ##############
# Customize group names here
admin-groups=cf-admins,sys-admins,ADMIN
channel-groups=cf-channels,USER
Expand All @@ -67,13 +65,44 @@ tag-groups=cf-tags,USER

############################## Elastic Network And HTTP ###############################

# Elasticsearch host
#elasticsearch.network.host: 169.254.42.56
# Elasticsearch, by default, binds itself to the 0.0.0.0 address, and listens
# on port [9200-9300] for HTTP traffic and on port [9300-9400] for node-to-node
# communication. (the range means that if the port is busy, it will automatically
# try the next port).

# Set the bind address specifically (IPv4 or IPv6):
#
# network.bind_host: 169.254.42.56

# Set the address other nodes will use to communicate with this node. If not
# set, it is automatically derived. It must point to an actual IP address.
#
# network.publish_host: 192.168.0.1

# Set both 'bind_host' and 'publish_host':
#
elasticsearch.network.host: localhost

# Set a custom port for the node to node communication (9300 by default):
#
#elasticsearch.transport.tcp.port: 9300

# Enable compression for all communication between nodes (disabled by default):
#
#transport.tcp.compress: true

# Set a custom port to listen for HTTP traffic:
#
elasticsearch.http.port: 9200

# Set a custom allowed content length:
#
#http.max_content_length: 100mb

# Disable HTTP completely:
#
#http.enabled: false

# Elasticsearch index names and types used by channelfinder, ensure that any changes here should be replicated in the mapping_definitions.sh
elasticsearch.tag.index = cf_tags
elasticsearch.property.index = cf_properties
Expand Down Expand Up @@ -101,8 +130,18 @@ aa.pva=false
aa.archive_property_name=archive
aa.archiver_property_name=archiver

# Set the auto pause behaviour
#
# Empty for no auto pause
# Or pvStatus to pause on pvStatus=Inactive
# Or match archive_property_name to pause on archive_property_name not existing
# Or both, i.e. aa.auto_pause=pvStatus,archive
#
aa.auto_pause=pvStatus,archive


############################## Metrics ###############################
#actuator
management.endpoints.web.exposure.include=prometheus
management.endpoints.web.exposure.include=prometheus, metrics, health, info
metrics.tags=
metrics.properties={'pvStatus': 'Active'}
metrics.properties={{'pvStatus', 'Active'}, {'pvStatus', 'Inactive'}}
40 changes: 6 additions & 34 deletions src/test/java/org/phoebus/channelfinder/ChannelRepositoryIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -476,40 +476,12 @@ public void setup() {

@AfterEach
public void cleanup() {
// clean up
testTags.forEach(tag -> {
try {
tagRepository.deleteById(tag.getName());
} catch (Exception e) {
System.out.println("Failed to clean up tag: " + tag.getName());
}
});
testUpdatedTags.forEach(tag -> {
try {
tagRepository.deleteById(tag.getName());
} catch (Exception e) {
System.out.println("Failed to clean up tag: " + tag.getName());
}
});
testProperties.forEach(property -> {
try {
propertyRepository.deleteById(property.getName());
} catch (Exception e) {
System.out.println("Failed to clean up property: " + property.getName());
}
});
testUpdatedProperties.forEach(property -> {
try {
propertyRepository.deleteById(property.getName());
} catch (Exception e) {
System.out.println("Failed to clean up property: " + property.getName());
}
});
cleanupTestChannels.forEach(channel -> {
if (channelRepository.existsById(channel.getName())) {
channelRepository.deleteById(channel.getName());
}
});

MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
map.set("~name", "*");
channelRepository.search(map).getChannels().forEach(c -> channelRepository.deleteById(c.getName()));
tagRepository.findAll().forEach(t -> tagRepository.deleteById(t.getName()));
propertyRepository.findAll().forEach(p -> propertyRepository.deleteById(p.getName()));
}

@AfterAll
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ public void setup() throws InterruptedException {
@AfterEach
public void cleanup() throws InterruptedException {
populateService.cleanupDB();
Thread.sleep(5000);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ public void setup() throws InterruptedException {
@AfterEach
public void cleanup() throws InterruptedException {
populateService.cleanupDB();
Thread.sleep(10000);
}

@BeforeAll
Expand Down
Loading

0 comments on commit 9b84977

Please sign in to comment.