Skip to content

Commit

Permalink
First attemt to send really collected data to the server
Browse files Browse the repository at this point in the history
  • Loading branch information
Serhii Vydiuk committed Dec 23, 2024
1 parent ef5e3ca commit e8f660a
Show file tree
Hide file tree
Showing 12 changed files with 88 additions and 50 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.readme.example;

import com.readme.dataextraction.UserDataCollector;
import org.springframework.context.annotation.Configuration;

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/java/readme-metrics-spring-boot-starter/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
</dependency>
<dependency>
<groupId>com.readme</groupId>
<artifactId>readme-metrics</artifactId>
<artifactId>metrics-core</artifactId>
<version>${readme-metrics.version}</version>
</dependency>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
package com.readme.starter.config;

import com.readme.dataextraction.RequestDataCollector;
import com.readme.dataextraction.UserDataCollector;
import com.readme.dataextraction.UserDataExtractor;
import com.readme.config.CoreConfig;

import com.readme.dataextraction.payload.RequestDataCollector;
import com.readme.dataextraction.user.UserDataCollector;
import com.readme.dataextraction.user.UserDataExtractor;
import com.readme.datatransfer.DataSender;
import com.readme.datatransfer.HttpDataSender;
import com.readme.starter.datacollection.DataCollectionFilter;
import com.readme.starter.datacollection.ServletDataPayloadAdapter;
import com.readme.starter.datacollection.userinfo.ServletUserDataCollector;
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import okhttp3.OkHttpClient;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
Expand All @@ -34,6 +37,8 @@
@Slf4j
public class DataCollectionAutoConfiguration {

private ReadmeConfigurationProperties readmeProperties;

@Bean
public FilterRegistrationBean<DataCollectionFilter> metricsFilter(
RequestDataCollector<ServletDataPayloadAdapter> requestDataCollector,
Expand All @@ -52,4 +57,15 @@ public UserDataCollector<ServletDataPayloadAdapter> userDataCollector(UserDataPr
log.info("readme-metrics: Creating of default user data collector");
return new ServletUserDataCollector(userDataProperties, extractionService);
}

@Bean
public DataSender dataSender() {
String readmeApiKey = readmeProperties.getReadmeApiKey();
CoreConfig coreConfig = CoreConfig.builder()
.readmeAPIKey(readmeApiKey)
.build();
OkHttpClient okHttpClient = new OkHttpClient();

return new HttpDataSender(okHttpClient, coreConfig);
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
package com.readme.starter.datacollection;

import com.readme.dataextraction.RequestDataCollector;
import com.readme.dataextraction.UserDataCollector;
import com.readme.domain.UserData;

import com.readme.dataextraction.payload.RequestDataCollector;
import com.readme.dataextraction.user.UserData;
import com.readme.dataextraction.user.UserDataCollector;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StreamUtils;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;

import java.io.IOException;

import static org.springframework.http.HttpMethod.GET;
import static org.springframework.http.HttpMethod.OPTIONS;


Expand Down Expand Up @@ -43,7 +41,7 @@ public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain
} else {
//TODO: Handle case if SDK user configured getting request user data from body, but GET req doesn't have it
//TODO: Validate user data. Collect request data only if user data is valid ?

//TODO: Does it make sense to collect everything except body before chain execution?....
chain.doFilter(request, response);
ServletDataPayloadAdapter payload =
new ServletDataPayloadAdapter(request, response);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,39 @@
package com.readme.starter.datacollection;

import com.readme.dataextraction.RequestDataCollector;
import com.readme.domain.UserData;
import com.readme.starter.config.ReadmeConfigurationProperties;

import com.readme.dataextraction.payload.ApiKeyMasker;
import com.readme.dataextraction.payload.PayloadData;
import com.readme.dataextraction.payload.RequestDataCollector;
import com.readme.dataextraction.user.UserData;
import com.readme.datatransfer.DataSender;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.UUID;

import static com.readme.dataextraction.payload.ApiKeyMasker.*;

@Slf4j
@AllArgsConstructor
@Component
public class ServletRequestDataCollector implements RequestDataCollector<ServletDataPayloadAdapter> {

private ReadmeConfigurationProperties readmeProperties;
private DataSender dataSender;

@Override
public void collect(ServletDataPayloadAdapter dataPayload, UserData userData) {
String readmeAPIKey = readmeProperties.getReadmeApiKey();
String maskedApiKey = mask(userData.getApiKey());
PayloadData payloadData = PayloadData.builder()
.apiKey(maskedApiKey)
.email(userData.getEmail())
.label(userData.getLabel())
.logId(UUID.randomUUID())
.requestBody(dataPayload.getRequestBody())
.build();

log.info(">>>>>>>> Sending data to the server with key {}", readmeAPIKey);
dataSender.send(payloadData);
log.info(">>>>>>>> Sending data to the server...");
log.info(">>>>>>>> and user data: {}", userData);
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
package com.readme.starter.datacollection.userinfo;

import com.readme.config.FieldMapping;
import com.readme.dataextraction.UserDataCollector;
import com.readme.dataextraction.UserDataExtractor;
import com.readme.dataextraction.UserDataSource;
import com.readme.domain.UserData;
import com.readme.dataextraction.user.UserData;
import com.readme.dataextraction.user.UserDataCollector;
import com.readme.dataextraction.user.UserDataExtractor;
import com.readme.dataextraction.user.UserDataSource;
import com.readme.starter.config.UserDataProperties;
import com.readme.starter.datacollection.ServletDataPayloadAdapter;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.stereotype.Component;

/**
* Responsible for selecting the appropriate {@link UserDataExtractor}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import com.auth0.jwt.interfaces.DecodedJWT;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.readme.dataextraction.UserDataExtractor;
import com.readme.dataextraction.user.UserDataExtractor;
import com.readme.starter.datacollection.ServletDataPayloadAdapter;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.readme.starter.datacollection;

import com.readme.dataextraction.RequestDataCollector;
import com.readme.dataextraction.UserDataCollector;
import com.readme.domain.UserData;
import com.readme.dataextraction.payload.RequestDataCollector;
import com.readme.dataextraction.user.UserData;
import com.readme.dataextraction.user.UserDataCollector;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package com.readme.starter.datacollection.userinfo;

import com.readme.config.FieldMapping;
import com.readme.dataextraction.UserDataExtractor;
import com.readme.dataextraction.UserDataSource;
import com.readme.domain.UserData;
import com.readme.dataextraction.user.UserData;
import com.readme.dataextraction.user.UserDataExtractor;
import com.readme.dataextraction.user.UserDataSource;
import com.readme.starter.config.UserDataProperties;
import com.readme.starter.datacollection.ServletDataPayloadAdapter;
import org.junit.jupiter.api.BeforeEach;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.readme.dataextraction.payload;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

public class ApiKeyMasker {

public static String mask(String apiKey) {
try {
String base64Hash = Base64.getEncoder()
.encodeToString(MessageDigest
.getInstance("SHA-512")
.digest(apiKey.getBytes(StandardCharsets.UTF_8)));

String last4Digits = apiKey.substring(apiKey.length() - 4);
return "sha512-" + base64Hash + "?" + last4Digits;
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("SHA-512 algorithm not available", e);
} catch (StringIndexOutOfBoundsException e) {
throw new IllegalArgumentException("API key must be at least 4 characters long", e);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public HttpDataSender(OkHttpClient client, CoreConfig coreConfig) {

@Override
public int send(PayloadData payloadData) {
if (payloadData != null && payloadData.getBody() != null && !payloadData.getBody().isEmpty()) {
if (payloadData != null) {
String encodedReadmeApiKey = getEncodedReadmeApiKey();
Request request = createRequest(payloadData, encodedReadmeApiKey);

Expand All @@ -45,7 +45,7 @@ public int send(PayloadData payloadData) {
}

private static Request createRequest(PayloadData payloadData, String encodedReadmeApiKey) {
RequestBody body = RequestBody.create(payloadData.getBody(), MediaType.get(APPLICATION_JSON_TYPE));
RequestBody body = RequestBody.create(payloadData.getRequestBody(), MediaType.get(APPLICATION_JSON_TYPE));
return new Request.Builder()
.url(README_METRICS_URL)
.header("Accept", APPLICATION_JSON_TYPE)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,6 @@ public void testSendOnSuccess() throws IOException {
assertEquals(200, httpDataSender.send(payloadData));
}

@Test
public void testSendOnBodyDoesntExist() throws IOException {
OkHttpClient client = mock(OkHttpClient.class);
Call call = mock(Call.class);
Response response = mockResponse();
PayloadData payloadData = PayloadData.builder().build();

when(client.newCall(any(Request.class))).thenReturn(call);
when(call.execute()).thenReturn(response);
HttpDataSender httpDataSender = new HttpDataSender(client, mockCoreConfig());

assertThrows(EmptyRequestBodyException.class, () -> httpDataSender.send(payloadData));
}

@NotNull
private static Response mockResponse() {
return new Response.Builder()
Expand All @@ -58,7 +44,7 @@ private static Response mockResponse() {

private static PayloadData mockRequestMetadata() {
return PayloadData.builder()
.body("body")
.requestBody("body")
.build();
}

Expand Down

0 comments on commit e8f660a

Please sign in to comment.