Skip to content

Commit

Permalink
UFAL/Matomo statistics with dimension (#813)
Browse files Browse the repository at this point in the history
* Updated the version of matomo dependency and tried to change request from Custom Variables to Dimension

* Added a custom dimension with item's handle URL

* Send custom dimension also in oai tracker

* Use only IPv4 address, the Matomo tracker has a problem with IPv6

* Do not change custom dimension when the Item is null

* First custom dimension should have ID '1'.

* Use a valid URL for Matomo tracker in the IT

* Configure handle custom dimension ID in the clarin-dspace.cfg

* Refactored ipv4 method to be more readable - return null

---------

Co-authored-by: Juraj Roka <[email protected]>
Co-authored-by: milanmajchrak <[email protected]>
Co-authored-by: milanmajchrak <[email protected]>
  • Loading branch information
4 people authored Nov 29, 2024
1 parent 9758648 commit 3486d2d
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 24 deletions.
4 changes: 2 additions & 2 deletions dspace-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -339,8 +339,8 @@
<dependencies>
<dependency>
<groupId>org.piwik.java.tracking</groupId>
<artifactId>matomo-java-tracker</artifactId>
<version>2.0</version>
<artifactId>matomo-java-tracker-java11</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import java.sql.SQLException;
import java.text.MessageFormat;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Objects;
import javax.servlet.http.HttpServletRequest;
Expand Down Expand Up @@ -69,7 +70,6 @@ public ClarinMatomoBitstreamTracker() {
@Override
protected void preTrack(Context context, MatomoRequest matomoRequest, Item item, HttpServletRequest request) {
super.preTrack(context, matomoRequest, item, request);

matomoRequest.setSiteId(siteId);
log.debug("Logging to site " + matomoRequest.getSiteId());
String itemIdentifier = getItemIdentifier(item);
Expand All @@ -82,6 +82,11 @@ protected void preTrack(Context context, MatomoRequest matomoRequest, Item item,
}
try {
matomoRequest.setPageCustomVariable(new CustomVariable("source", "bitstream"), 1);
// Add the Item handle into the request as a custom dimension
LinkedHashMap<Long, Object> handleDimension = new LinkedHashMap<>();
handleDimension.put(configurationService.getLongProperty("matomo.custom.dimension.handle.id",
1L), item.getHandle());
matomoRequest.setDimensions(handleDimension);
} catch (MatomoException e) {
log.error(e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
*/
package org.dspace.app.statistics.clarin;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Calendar;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.CompletableFuture;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.logging.log4j.Logger;
import org.dspace.content.Item;
import org.dspace.content.factory.ClarinServiceFactory;
Expand All @@ -23,6 +23,7 @@
import org.dspace.services.factory.DSpaceServicesFactory;
import org.matomo.java.tracking.MatomoException;
import org.matomo.java.tracking.MatomoRequest;
import org.matomo.java.tracking.parameters.AcceptLanguage;

/**
* The statistics Tracker for Matomo. This class prepare and send the track GET request to the `/matomo.php`
Expand Down Expand Up @@ -99,13 +100,13 @@ protected MatomoRequest createMatomoRequest(HttpServletRequest request, String p
*/
protected void preTrack(Context context, MatomoRequest matomoRequest, Item item, HttpServletRequest request) {
if (StringUtils.isNotBlank(request.getHeader("referer"))) {
matomoRequest.setHeaderUserAgent(request.getHeader("referer"));
matomoRequest.setReferrerUrl(request.getHeader("referer"));
}
if (StringUtils.isNotBlank(request.getHeader("user-agent"))) {
matomoRequest.setHeaderUserAgent(request.getHeader("user-agent"));
}
if (StringUtils.isNotBlank(request.getHeader("accept-language"))) {
matomoRequest.setHeaderUserAgent(request.getHeader("accept-language"));
matomoRequest.setHeaderAcceptLanguage(AcceptLanguage.fromHeader(request.getHeader("accept-language")));
}

// Creating a calendar using getInstance method
Expand Down Expand Up @@ -134,18 +135,13 @@ protected void preTrack(Context context, MatomoRequest matomoRequest, Item item,
* @param matomoRequest prepared MatomoRequest for sending
*/
public void sendTrackingRequest(MatomoRequest matomoRequest) {
try {
Future<HttpResponse> response = tracker.sendRequestAsync(matomoRequest);
// usually not needed:
HttpResponse httpResponse = response.get();
int statusCode = httpResponse.getStatusLine().getStatusCode();
if (statusCode > 399) {
// problem
log.error("Matomo tracker error the response has status code: " + statusCode);
CompletableFuture<MatomoRequest> completableFuture = tracker.sendRequestAsync(matomoRequest);

completableFuture.whenComplete((result, exception) -> {
if (exception != null) {
log.error("Matomo tracker error - the response exception message: {}", exception.getMessage());
}
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
});
}

protected String getFullURL(HttpServletRequest request) {
Expand All @@ -164,21 +160,35 @@ protected String getFullURL(HttpServletRequest request) {
}

/**
* Get IpAddress of the current user which throws this statistic event
* Get IpAddress of the current user which throws this statistic event. Return only the first valid IPv4 address
* because the Matomo tracker has a problem with IPv6 addresses.
*
* @param request current request
* @return
* @return only the first valid IPv4 address
*/
protected String getIpAddress(HttpServletRequest request) {
String ip = "";
String header = request.getHeader("X-Forwarded-For");
if (header == null) {
header = request.getRemoteAddr();
}
if (header != null) {
String[] ips = header.split(", ");
ip = ips.length > 0 ? ips[0] : "";
for (String candidateIp : ips) {
// Validate if it's an IPv4 address
if (isIPv4Address(candidateIp)) {
return candidateIp;
}
}
}
return null;
}

private boolean isIPv4Address(String ip) {
try {
InetAddress inetAddress = InetAddress.getByName(ip);
return inetAddress.getHostAddress().equals(ip) && inetAddress instanceof java.net.Inet4Address;
} catch (UnknownHostException e) {
return false; // Not a valid IP address
}
return ip;
}
}
4 changes: 4 additions & 0 deletions dspace-api/src/test/data/dspaceFolder/config/local.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,10 @@ webui.supported.locales = en
# When title is something like "Type-bind test" the type-bind field will popped up
submit.type-bind.field = dc.type,dc.identifier.citation=>dc.title

# The configuration for the Matomo tracker must have a valid URL, as it will throw an exception if it does not.
matomo.tracker.host.url = http://localhost:8135/matomo.php

autocomplete.custom.separator.solr-subject_ac = \\|\\|\\|
autocomplete.custom.separator.solr-title_ac = \\|\\|\\|
autocomplete.custom.allowed = solr-author_ac,solr-publisher_ac,solr-dataProvider_ac,solr-dctype_ac,solr-subject_ac,solr-handle_title_ac,json_static-iso_langs.json,solr-title_ac

1 change: 1 addition & 0 deletions dspace/config/clarin-dspace.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ matomo.site.id = 1
matomo.tracker.bitstream.site_id = 1
matomo.tracker.oai.site_id = 1
matomo.tracker.host.url = http://url:port/matomo.php
matomo.custom.dimension.handle.id = 1
statistics.cache-server.uri = http://cache-server.none

#### Statistic usage reports ####
Expand Down

0 comments on commit 3486d2d

Please sign in to comment.