Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
7 changes: 6 additions & 1 deletion .github/workflows/maven.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,16 @@ jobs:
distribution: adopt
cache: maven

- run: free -h
- run: grep -E 'MemTotal|MemFree|MemAvailable|SwapTotal|SwapFree' /proc/meminfo
- run: vmstat -s
- run: java -XshowSettings:vm -version

- name: Run the tests in Maven
timeout-minutes: 15
# We need a timeout here
env:
MAVEN_OPTS: -Xmx12g -Xms4g -XX:MaxMetaspaceSize=1g
MAVEN_OPTS: -Xmx20g
run: mvn --batch-mode --no-transfer-progress --update-snapshots verify

- uses: actions/upload-artifact@v4
Expand Down
6 changes: 5 additions & 1 deletion matchbox-engine/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,12 @@
<build>
<finalName>matchbox-engine</finalName>
<plugins>
<!-- This is to run the unit tests -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-Xmx12g</argLine>
<argLine>-Xmx20g</argLine>
<reuseForks>true</reuseForks>
<forkCount>1</forkCount>
</configuration>
Expand Down Expand Up @@ -178,6 +179,9 @@
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<redirectTestOutputToFile>true</redirectTestOutputToFile>
<argLine>-Xmx20g</argLine>
<forkCount>1</forkCount>
<reuseForks>true</reuseForks>
</configuration>
<executions>
<execution>
Expand Down
30 changes: 30 additions & 0 deletions matchbox-server/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -303,12 +303,42 @@
</configuration>
</plugin>

<!-- This is to run the unit tests -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-Xmx20g</argLine>
<reuseForks>true</reuseForks>
<forkCount>1</forkCount>
</configuration>
<executions>
<execution>
<id>default-test</id>
<phase>test</phase>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>

<!-- This is to run the integration tests -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<redirectTestOutputToFile>true</redirectTestOutputToFile>
<argLine>-Xmx20g</argLine>
<forkCount>1</forkCount>
<reuseForks>true</reuseForks>
</configuration>
<executions>
<execution>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ca.uhn.fhir.jpa.starter;

import ch.ahdis.matchbox.MatchboxRestfulServer;
import ch.ahdis.matchbox.config.MatchboxMetricsConfig;
import ch.ahdis.matchbox.config.MatchboxStaticResourceConfig;
import ch.ahdis.matchbox.config.MatchboxTxConfig;
import ch.ahdis.matchbox.spring.MatchboxEventListener;
Expand Down Expand Up @@ -39,7 +40,8 @@
RegistryWs.class,
MatchboxStaticResourceConfig.class,
McpServerConfig.class,
MatchboxTxConfig.class
MatchboxTxConfig.class,
MatchboxMetricsConfig.class
})
public class Application extends SpringBootServletInitializer {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package ch.ahdis.matchbox.config;

import ch.ahdis.matchbox.packages.MatchboxImplementationGuideProvider;
import ch.ahdis.matchbox.util.EngineSessionCache;
import ch.ahdis.matchbox.util.MatchboxEngineSupport;
import ch.ahdis.matchbox.util.metrics.MatchboxMetrics;
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.binder.MeterBinder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
* Configuration for collecting Matchbox metrics and exposing them via Micrometer.
**/
@Configuration
public class MatchboxMetricsConfig {
private static final String ENGINE_UNIT = "engines";

@Bean
public MeterBinder exposeNumberOfCachedEngines(final MatchboxEngineSupport engineSupport) {
final var engineCache = engineSupport.getSessionCache();
return registry -> {
Gauge.builder("matchbox.engines.cached.transient.number", engineCache::numberOfTransientEngines)
.description("Number of cached expiring Matchbox engines in the server")
.baseUnit(ENGINE_UNIT)
.register(registry);
Comment thread
qligier marked this conversation as resolved.
Gauge.builder("matchbox.engines.cached.permanent.number", engineCache::numberOfPermanentEngines)
.description("Number of cached immutable Matchbox engines in the server")
.baseUnit(ENGINE_UNIT)
.register(registry);
};
}

@Bean
public MeterBinder exposeNumberOfIgs(final MatchboxImplementationGuideProvider implementationGuideProvider) {
return registry -> Gauge.builder("matchbox.igs.number", implementationGuideProvider::count)
.description("Number of installed ImplementationGuides")
.baseUnit("ImplementationGuides")
.register(registry);
Comment thread
qligier marked this conversation as resolved.
}

@Bean
public MatchboxMetrics matchboxMetrics(final MeterRegistry meterRegistry) {
return new MatchboxMetrics(meterRegistry);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Set;
import java.util.*;

import ch.ahdis.matchbox.util.metrics.MatchboxMetrics;
import jakarta.servlet.ServletOutputStream;
/*
* #%L
Expand Down Expand Up @@ -59,8 +59,6 @@
import org.hl7.fhir.r5.model.*;

import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;

/**
* StructureMapTransformProvider
Expand All @@ -70,6 +68,9 @@ public class StructureMapTransformProvider extends StructureMapResourceProvider
@Autowired
protected MatchboxEngineSupport matchboxEngineSupport;

@Autowired(required = false)
private Optional<MatchboxMetrics> matchboxMetrics;

private final FhirContext fhirR5Context = FhirContext.forR5Cached();

@Override
Expand Down Expand Up @@ -97,6 +98,7 @@ public MethodOutcome update(final HttpServletRequest theRequest,
@Operation(name = "$transform", type = StructureMap.class, manualResponse = true, manualRequest = true)
public void manualInputAndOutput(final HttpServletRequest theServletRequest,
final HttpServletResponse theServletResponse) throws IOException {
this.matchboxMetrics.ifPresent(MatchboxMetrics::addTransformation);
// Parse the request body, it is either a Parameters resource, or any resource
final String body = new String(theServletRequest.getInputStream().readAllBytes()).trim();
@Nullable String resource = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -547,4 +547,9 @@ public void installFromInternetRegistry(final String packageId, final String pac
.setVersion(packageVersion)
);
}

Comment thread
qligier marked this conversation as resolved.
@Override
public long count() {
return this.myPackageVersionDao.count();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -551,4 +551,9 @@ public void installFromInternetRegistry(final String packageId, final String pac
.setVersion(packageVersion)
);
}

Comment thread
qligier marked this conversation as resolved.
@Override
public long count() {
return this.myPackageVersionDao.count();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -533,4 +533,9 @@ public void installFromInternetRegistry(final String packageId, final String pac
.setVersion(packageVersion)
);
}

Comment thread
qligier marked this conversation as resolved.
@Override
public long count() {
return this.myPackageVersionDao.count();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,9 @@ public interface MatchboxImplementationGuideProvider {
* Installs the given ImplementationGuide from the internet registry.
*/
void installFromInternetRegistry(final String packageId, final String packageVersion);

/**
* Counts the number of installed ImplementationGuides.
*/
long count();
}
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,11 @@ public String getSessionId(ValidationEngine validationEngine) {
return null;
}

public int numberOfPermanentEngines() {
return cachedSessionsNoTimeout.size();
}

public int numberOfTransientEngines() {
return cachedSessionIds.size();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,10 @@ public String getSessionId(final MatchboxEngine engine) {
return this.sessionCache.getSessionId(engine);
}

public EngineSessionCache getSessionCache() {
return this.sessionCache;
}

public boolean isInitialized() {
return initialized;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package ch.ahdis.matchbox.util.metrics;

import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;

import java.time.Duration;

/**
* The class holding different metrics that Matchbox may collect.
*
* @see ch.ahdis.matchbox.config.MatchboxMetricsConfig
**/
public class MatchboxMetrics {

private final Counter validationCounter;
private final Timer validationDurationTimer;
private final Counter transformationCounter;

public MatchboxMetrics(final MeterRegistry meterRegistry) {
this.validationCounter = Counter.builder("matchbox.validation.count")
.description("Number of FHIR resources validated by Matchbox")
.baseUnit("validations")
.register(meterRegistry);
this.validationDurationTimer = Timer.builder("matchbox.validation.duration")
.description("Duration of FHIR resource validation by Matchbox")
.percentilePrecision(1)
.maximumExpectedValue(Duration.ofSeconds(60))
.register(meterRegistry);
this.transformationCounter = Counter.builder("matchbox.transformation.count")
.description("Number of FHIR resources transformed by Matchbox")
.baseUnit("transformations")
.register(meterRegistry);
}

public void addValidation() {
this.validationCounter.increment();
}

public void addValidationDuration(final Duration duration) {
this.validationDurationTimer.record(duration);
}

public void addTransformation() {
this.transformationCounter.increment();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import ch.ahdis.matchbox.CliContext;
import ch.ahdis.matchbox.config.MatchboxFhirVersion;
import ch.ahdis.matchbox.util.MatchboxEngineSupport;
import ch.ahdis.matchbox.util.metrics.MatchboxMetrics;
import ch.ahdis.matchbox.validation.matchspark.LLMConnector;
import ch.ahdis.matchbox.engine.MatchboxEngine;
import ch.ahdis.matchbox.engine.cli.VersionUtil;
Expand All @@ -38,14 +39,10 @@
import org.checkerframework.checker.nullness.qual.NonNull;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r5.model.CodeableConcept;
import org.hl7.fhir.r5.model.*;
import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat;
import org.hl7.fhir.r5.extensions.ExtensionDefinitions;
import org.hl7.fhir.r5.model.Duration;
import org.hl7.fhir.r5.model.OperationOutcome;
import org.hl7.fhir.r5.model.StringType;
import org.hl7.fhir.r5.utils.EOperationOutcome;
import org.hl7.fhir.r5.model.UriType;
import org.hl7.fhir.r5.utils.OperationOutcomeUtilities;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -60,6 +57,7 @@
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import static ch.ahdis.matchbox.util.MatchboxServerUtils.addExtension;

Expand Down Expand Up @@ -90,6 +88,9 @@ public class ValidationProvider {
@Autowired
private PlatformTransactionManager myTxManager;

@Autowired(required = false)
private Optional<MatchboxMetrics> matchboxMetrics;

// @Operation(name = "$canonical", manualRequest = true, idempotent = true, returnParameters = {
// @OperationParam(name = "return", type = IBase.class, min = 1, max = 1) })
// public IBaseResource canonical(HttpServletRequest theRequest) {
Expand All @@ -114,6 +115,7 @@ public class ValidationProvider {
@OperationParam(name = "return", type = IBase.class, min = 1, max = 1)})
public IBaseResource validate(final HttpServletRequest theRequest) {
log.debug("$validate");
this.matchboxMetrics.ifPresent(MatchboxMetrics::addValidation);

final var sw = new StopWatch();
sw.startTask("Total");
Expand Down Expand Up @@ -222,6 +224,7 @@ public IBaseResource validate(final HttpServletRequest theRequest) {

long millis = sw.getMillis();
log.debug("Validation time: {}", sw);
this.matchboxMetrics.ifPresent(m -> m.addValidationDuration(java.time.Duration.ofMillis(millis)));

var oo = this.getOperationOutcome(sha3Hex, messages, profile, engine, millis, cliContext);

Expand Down
Loading
Loading