Skip to content

Commit 5818d83

Browse files
Java Metrics SDK implementation (Spring Boot2/SpringBoot3) (#1179)
1 parent c2acf3b commit 5818d83

File tree

119 files changed

+7599
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

119 files changed

+7599
-0
lines changed

.github/workflows/codeql-analysis.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ jobs:
2222
- javascript
2323
- python
2424
- ruby
25+
- java
2526

2627
steps:
2728
- name: Checkout repository
@@ -34,7 +35,15 @@ jobs:
3435
languages: ${{ matrix.language }}
3536

3637
- name: Autobuild
38+
if: matrix.language != 'java'
3739
uses: github/codeql-action/autobuild@v3
3840

41+
- name: Build for Java and Kotlin
42+
if: matrix.language == 'java'
43+
run: |
44+
mvn clean install -f packages/java/metrics-core/pom.xml
45+
mvn clean install -f packages/java/metrics-spring/pom.xml
46+
mvn clean install -f packages/java/metrics-spring2/pom.xml
47+
3948
- name: Perform CodeQL Analysis
4049
uses: github/codeql-action/analyze@v3

.github/workflows/java.yaml

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
name: java
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
paths:
8+
- 'packages/java/**'
9+
10+
jobs:
11+
build-and-deploy-core:
12+
name: Build and Deploy metrics-core
13+
runs-on: ubuntu-latest
14+
15+
steps:
16+
- name: Checkout code
17+
uses: actions/checkout@v4
18+
19+
- name: Set up JDK 17
20+
uses: actions/setup-java@v3
21+
with:
22+
distribution: 'temurin'
23+
java-version: '17'
24+
25+
- name: Configure Maven settings.xml
26+
run: echo "${{ secrets.MAVEN_SETTINGS }}" > ~/.m2/settings.xml
27+
28+
- name: Build & Test metrics-core
29+
working-directory: packages/java
30+
run: mvn clean verify
31+
32+
- name: Import GPG Key
33+
run: |
34+
echo "$GPG_PRIVATE_KEY" | base64 --decode | gpg --batch --import
35+
env:
36+
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
37+
38+
- name: Deploy metrics-core
39+
working-directory: packages/java
40+
run: mvn deploy -Dgpg.passphrase=${{ secrets.GPG_PASSPHRASE }}
41+
42+
build-and-deploy-for-spring3:
43+
name: Build and Deploy metrics-spring library for Spring Boot 3+
44+
needs: build-and-deploy-core
45+
runs-on: ubuntu-latest
46+
47+
steps:
48+
- name: Checkout code
49+
uses: actions/checkout@v4
50+
51+
- name: Set up JDK 17
52+
uses: actions/setup-java@v3
53+
with:
54+
distribution: 'temurin'
55+
java-version: '17'
56+
57+
- name: Configure Maven settings.xml
58+
run: echo "${{ secrets.MAVEN_SETTINGS }}" > ~/.m2/settings.xml
59+
60+
- name: Build & Test metrics-spring
61+
working-directory: packages/java/metrics-spring
62+
run: mvn clean verify
63+
64+
- name: Import GPG Key
65+
run: |
66+
echo "$GPG_PRIVATE_KEY" | base64 --decode | gpg --batch --import
67+
env:
68+
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
69+
70+
- name: Deploy metrics-spring
71+
working-directory: packages/java/metrics-spring
72+
run: mvn deploy -Dgpg.passphrase=${{ secrets.GPG_PASSPHRASE }}
73+
74+
build-and-deploy-for-spring2:
75+
name: Build and Deploy metrics-spring library for Spring Boot 2+
76+
needs: build-and-deploy-core
77+
runs-on: ubuntu-latest
78+
79+
steps:
80+
- name: Checkout code
81+
uses: actions/checkout@v4
82+
83+
- name: Set up JDK 17
84+
uses: actions/setup-java@v3
85+
with:
86+
distribution: 'temurin'
87+
java-version: '17'
88+
89+
- name: Configure Maven settings.xml
90+
run: echo "${{ secrets.MAVEN_SETTINGS }}" > ~/.m2/settings.xml
91+
92+
- name: Build & Test metrics-spring2
93+
working-directory: packages/java/metrics-spring2
94+
run: mvn clean verify
95+
96+
- name: Import GPG Key
97+
run: |
98+
echo "$GPG_PRIVATE_KEY" | base64 --decode | gpg --batch --import
99+
env:
100+
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
101+
102+
- name: Deploy metrics-spring2
103+
working-directory: packages/java/metrics-spring2
104+
run: mvn deploy -Dgpg.passphrase=${{ secrets.GPG_PASSPHRASE }}
105+

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,10 @@ node_modules/
44
packages/*/.nyc_output/
55
packages/*/coverage/
66
packages/*/node_modules/
7+
8+
### IntelliJ IDEA ###
9+
.idea
10+
*.iws
11+
*.iml
12+
*.ipr
13+

packages/java/.gitignore

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
target/
2+
!.mvn/wrapper/maven-wrapper.jar
3+
!**/src/main/**/target/
4+
!**/src/test/**/target/
5+
../*
6+
7+
### IntelliJ IDEA ###
8+
.idea/
9+
*.iws
10+
*.iml
11+
*.ipr
12+
13+
### Eclipse ###
14+
.apt_generated
15+
.classpath
16+
.factorypath
17+
.project
18+
.settings
19+
.springBeans
20+
.sts4-cache
21+
22+
### VS Code ###
23+
.vscode/
24+
25+
### Mac OS ###
26+
.DS_Store
27+
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
target/
2+
!.mvn/wrapper/maven-wrapper.jar
3+
!**/src/main/**/target/
4+
!**/src/test/**/target/
5+
6+
### STS ###
7+
.apt_generated
8+
.classpath
9+
.factorypath
10+
.project
11+
.settings
12+
.springBeans
13+
.sts4-cache
14+
15+
### IntelliJ IDEA ###
16+
.idea
17+
*.iws
18+
*.iml
19+
*.ipr
20+
21+
### VS Code ###
22+
.vscode/
23+
24+
.DS_Store
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
wrapperVersion=3.3.2
18+
distributionType=only-script
19+
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# SpringMetricsExample
2+
3+
The application is a REST web-service. It is an example of using Java metrics SDK.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
<parent>
6+
<groupId>org.springframework.boot</groupId>
7+
<artifactId>spring-boot-starter-parent</artifactId>
8+
<version>3.3.4</version>
9+
<!-- <version>2.7.18</version>-->
10+
<relativePath/>
11+
</parent>
12+
<groupId>com.readme</groupId>
13+
<artifactId>spring-metrics-example</artifactId>
14+
<version>0.0.1-SNAPSHOT</version>
15+
<name>spring-metrics-example</name>
16+
<description>Example project to test metrics-sdk</description>
17+
18+
<properties>
19+
<java.version>21</java.version>
20+
</properties>
21+
22+
<dependencies>
23+
<dependency>
24+
<groupId>com.readme</groupId>
25+
<artifactId>metrics-spring</artifactId>
26+
<!-- <artifactId>metrics-spring2</artifactId>-->
27+
<version>0.1.0</version>
28+
</dependency>
29+
<dependency>
30+
<groupId>org.springframework.boot</groupId>
31+
<artifactId>spring-boot-starter-web</artifactId>
32+
</dependency>
33+
<dependency>
34+
<groupId>org.springframework.boot</groupId>
35+
<artifactId>spring-boot-starter-test</artifactId>
36+
<scope>test</scope>
37+
</dependency>
38+
</dependencies>
39+
40+
<build>
41+
<plugins>
42+
<plugin>
43+
<groupId>org.springframework.boot</groupId>
44+
<artifactId>spring-boot-maven-plugin</artifactId>
45+
</plugin>
46+
</plugins>
47+
</build>
48+
49+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.owl.example;
2+
3+
import com.readme.core.dataextraction.LogOptions;
4+
import com.readme.core.dataextraction.payload.user.UserData;
5+
import com.readme.core.dataextraction.payload.user.UserDataCollector;
6+
import com.readme.spring.datacollection.ServletDataPayloadAdapter;
7+
import org.springframework.context.annotation.Bean;
8+
import org.springframework.context.annotation.Configuration;
9+
10+
import java.util.List;
11+
12+
/**
13+
* Configuration class for customizing the strategy to collect user data.
14+
*
15+
* <p>This configuration provides a custom implementation of {@link UserDataCollector},
16+
* which overrides the default behavior provided by the SDK. It allows developers
17+
* to specify their own logic for extracting user-specific information, such as API keys,
18+
* email addresses, or labels, from the incoming HTTP requests.</p>
19+
*
20+
* <p>In this example, the API key is extracted from the HTTP headers using the header
21+
* "X-User-Name", while the email and label fields are hardcoded with custom values.
22+
* Developers can modify this logic to suit their application's requirements.</p>
23+
*
24+
* <p>By defining this bean, Spring Boot's auto-configuration will automatically use
25+
* this custom implementation instead of the default {@link UserDataCollector}.</p>
26+
*/
27+
@Configuration
28+
public class CustomUserDataCollectorConfig {
29+
30+
@Bean
31+
public UserDataCollector<ServletDataPayloadAdapter> customUserDataCollector() {
32+
return payloadAdapter -> {
33+
String apiKey = payloadAdapter.getRequestHeaders().get("x-user-name");
34+
return UserData.builder()
35+
.apiKey(apiKey)
36+
37+
.label("owl-label")
38+
.build();
39+
};
40+
}
41+
42+
@Bean
43+
public LogOptions logOptions() {
44+
return LogOptions.builder()
45+
.baseLogUrl("http://baseurl.abcd")
46+
.bufferLength(1)
47+
.build();
48+
}
49+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package com.owl.example;
2+
3+
import com.readme.core.datatransfer.har.HttpStatus;
4+
import org.springframework.http.HttpHeaders;
5+
import org.springframework.http.MediaType;
6+
import org.springframework.http.ResponseEntity;
7+
import org.springframework.web.bind.annotation.*;
8+
9+
import java.util.*;
10+
11+
/**
12+
* OwlController is a sample REST controller intended for demonstration and testing purposes.
13+
* <p>
14+
* It simulates typical HTTP requests and responses to showcase how the ReadMe Metrics SDK
15+
* integrates into a Spring Boot application.
16+
* <p>
17+
* This controller is not intended for production use and serves only as an example endpoint
18+
* to test how the SDK logs and processes different request types.
19+
*/
20+
@RestController
21+
public class OwlController {
22+
23+
private final Map<String, String> owlStorage = new HashMap<>();
24+
25+
public OwlController() {
26+
owlStorage.put("1", "Default Owl");
27+
}
28+
29+
@GetMapping("/owl/{id}")
30+
public String getOwlById(@PathVariable String id) {
31+
return "Owl with id " + id;
32+
}
33+
34+
@GetMapping("/owls")
35+
public Collection<String> getAllOwl() {
36+
return owlStorage.values();
37+
}
38+
39+
@PutMapping("/owl/{owlName}")
40+
public ResponseEntity<String> createOwl(@PathVariable String owlName, @RequestBody String body) {
41+
UUID birdId = UUID.randomUUID();
42+
owlStorage.put(birdId.toString(), owlName);
43+
44+
String responseBody = "Bird " + owlName + " created a bird with id: " + birdId + "\n" +
45+
"Creation request body: \n" + body;
46+
47+
HttpHeaders headers = new HttpHeaders();
48+
headers.add("bird-id", birdId.toString());
49+
headers.add("bird-token", Base64.getEncoder()
50+
.encodeToString(birdId.toString()
51+
.getBytes()));
52+
53+
return ResponseEntity.status(HttpStatus.CREATED.getCode())
54+
.headers(headers)
55+
.body(responseBody);
56+
}
57+
58+
@PutMapping(value = "/owl/urlencoded/{owlName}", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
59+
public ResponseEntity<String> createOwlUrlencoded(@RequestParam Map<String, String> params) {
60+
UUID birdId = UUID.randomUUID();
61+
62+
String responseBody = "Created a bird with id: " + birdId + "\n" +
63+
"Creation request urlencoded body: \n" + params;
64+
65+
HttpHeaders headers = new HttpHeaders();
66+
headers.add("bird-id", birdId.toString());
67+
headers.add("bird-token", Base64.getEncoder()
68+
.encodeToString(birdId.toString()
69+
.getBytes()));
70+
71+
return ResponseEntity.status(HttpStatus.CREATED.getCode())
72+
.headers(headers)
73+
.body(responseBody);
74+
}
75+
76+
}

0 commit comments

Comments
 (0)