Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate version information to device.runtimeVersions #141

Merged
merged 9 commits into from
Apr 25, 2019
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## 3.X.X (TBD)

* Migrate version information to device.runtimeVersions
[#141](https://github.com/bugsnag/bugsnag-java/pull/141)

## 3.4.6 (2019-04-16)

* Swallow Throwables thrown when configuring bugsnag appender
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.springframework.context.annotation.Import;
import org.springframework.core.SpringVersion;

import java.util.Map;
import javax.annotation.PostConstruct;

/**
Expand All @@ -27,17 +28,33 @@ public class BugsnagSpringConfiguration {
* Add a callback to add the version of Spring used by the application
*/
@Bean
Callback springVersionCallback() {
Callback springVersionErrorCallback() {
Callback callback = new Callback() {
@Override
public void beforeNotify(Report report) {
report.addToTab("device", "springVersion", SpringVersion.getVersion());
addSpringRuntimeVersion(report.getDevice());
}
};
bugsnag.addCallback(callback);
return callback;
}

@Bean
BeforeSendSession springVersionSessionCallback() {
BeforeSendSession beforeSendSession = new BeforeSendSession() {
@Override
public void beforeSendSession(SessionPayload payload) {
addSpringRuntimeVersion(payload.getDevice());
}
};
bugsnag.addBeforeSendSession(beforeSendSession);
return beforeSendSession;
}

private void addSpringRuntimeVersion(Map<String, Object> device) {
Diagnostics.addDeviceRuntimeVersion(device, "springFramework", SpringVersion.getVersion());
}

@Bean
ScheduledTaskBeanLocator scheduledTaskBeanLocator() {
return new ScheduledTaskBeanLocator();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

import java.util.Map;
import javax.servlet.ServletRequestListener;

/**
Expand All @@ -26,17 +27,33 @@ class SpringBootConfiguration {
* Add a callback to add the version of Spring Boot used by the application.
*/
@Bean
Callback springBootVersionCallback() {
Callback springBootVersionErrorCallback() {
Callback callback = new Callback() {
@Override
public void beforeNotify(Report report) {
report.addToTab("device", "springBootVersion", SpringBootVersion.getVersion());
addSpringRuntimeVersion(report.getDevice());
}
};
bugsnag.addCallback(callback);
return callback;
}

@Bean
BeforeSendSession springBootVersionSessionCallback() {
BeforeSendSession beforeSendSession = new BeforeSendSession() {
@Override
public void beforeSendSession(SessionPayload payload) {
addSpringRuntimeVersion(payload.getDevice());
}
};
bugsnag.addBeforeSendSession(beforeSendSession);
return beforeSendSession;
}

private void addSpringRuntimeVersion(Map<String, Object> device) {
Diagnostics.addDeviceRuntimeVersion(device, "springBoot", SpringBootVersion.getVersion());
}

/**
* The {@link com.bugsnag.servlet.BugsnagServletContainerInitializer} does not work for Spring Boot, need to
* register the {@link BugsnagServletRequestListener} using a Spring Boot
Expand Down
10 changes: 6 additions & 4 deletions bugsnag-spring/src/test/java/com/bugsnag/SpringMvcTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -157,16 +157,18 @@ public void requestMetadataSetCorrectly() {
}

@Test
@SuppressWarnings("unchecked")
public void springVersionSetCorrectly() {
callRuntimeExceptionEndpoint();

Report report = verifyAndGetReport(delivery);

// Check that the Spring version is set as expected
@SuppressWarnings(value = "unchecked") Map<String, Object> deviceMetadata =
(Map<String, Object>) report.getMetaData().get("device");
assertEquals(SpringVersion.getVersion(), deviceMetadata.get("springVersion"));
assertEquals(SpringBootVersion.getVersion(), deviceMetadata.get("springBootVersion"));
Map<String, Object> deviceMetadata = report.getDevice();
Map<String, Object> runtimeVersions =
(Map<String, Object>) deviceMetadata.get("runtimeVersions");
assertEquals(SpringVersion.getVersion(), runtimeVersions.get("springFramework"));
assertEquals(SpringBootVersion.getVersion(), runtimeVersions.get("springBoot"));
}

@Test
Expand Down
5 changes: 5 additions & 0 deletions bugsnag/src/main/java/com/bugsnag/BeforeSendSession.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.bugsnag;

interface BeforeSendSession {
void beforeSendSession(SessionPayload payload);
}
4 changes: 4 additions & 0 deletions bugsnag/src/main/java/com/bugsnag/Bugsnag.java
Original file line number Diff line number Diff line change
Expand Up @@ -665,4 +665,8 @@ public static Set<Bugsnag> uncaughtExceptionClients() {
}
return Collections.emptySet();
}

void addBeforeSendSession(BeforeSendSession beforeSendSession) {
sessionTracker.addBeforeSendSession(beforeSendSession);
}
}
22 changes: 22 additions & 0 deletions bugsnag/src/main/java/com/bugsnag/Diagnostics.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,17 @@ private Map<String, Object> getDefaultDeviceInfo() {
map.put("hostname", DeviceCallback.getHostnameValue());
map.put("osName", System.getProperty("os.name"));
map.put("osVersion", System.getProperty("os.version"));
map.put("runtimeVersions", getRuntimeVersions());
return map;
}

private Map<String, String> getRuntimeVersions() {
Map<String, String> runtimeVersions = new HashMap<String, String>();
runtimeVersions.put("javaType", System.getProperty("java.runtime.name"));
runtimeVersions.put("javaVersion", System.getProperty("java.runtime.version"));
return runtimeVersions;
}

private Map<String, Object> getDefaultAppInfo(Configuration configuration) {
Map<String, Object> map = new HashMap<String, Object>();

Expand All @@ -37,4 +45,18 @@ private Map<String, Object> getDefaultAppInfo(Configuration configuration) {
}
return map;
}

@SuppressWarnings("unchecked")
static void addDeviceRuntimeVersion(Map<String, Object> device, String key, Object value) {
Object obj = device.get("runtimeVersions");
Map<String, Object> runtimeVersions;

if (obj instanceof Map) {
runtimeVersions = (Map<String, Object>) obj;
} else { // fallback to creating a new map if payload was mutated
runtimeVersions = new HashMap<String, Object>();
device.put("runtimeVersions", runtimeVersions);
}
runtimeVersions.put(key, value);
}
}
10 changes: 10 additions & 0 deletions bugsnag/src/main/java/com/bugsnag/SessionTracker.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class SessionTracker {

private final Semaphore flushingRequest = new Semaphore(1);
private final AtomicBoolean shuttingDown = new AtomicBoolean();
private final Collection<BeforeSendSession> sessionCallbacks = new ConcurrentLinkedQueue<BeforeSendSession>();

SessionTracker(Configuration configuration) {
this.config = configuration;
Expand Down Expand Up @@ -88,6 +89,11 @@ private void sendSessions(Date now) {
Collection<SessionCount> requestValues
= new ArrayList<SessionCount>(enqueuedSessionCounts);
SessionPayload payload = new SessionPayload(requestValues, config);

for (BeforeSendSession callback : sessionCallbacks) {
callback.beforeSendSession(payload);
}

Delivery delivery = config.sessionDelivery;
delivery.deliver(config.serializer, payload, config.getSessionApiHeaders());
enqueuedSessionCounts.removeAll(requestValues);
Expand All @@ -102,4 +108,8 @@ void shutdown() {
sendSessions(new Date(Long.MAX_VALUE)); // flush all remaining sessions
}
}

void addBeforeSendSession(BeforeSendSession beforeSendSession) {
sessionCallbacks.add(beforeSendSession);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,6 @@ public static void initializeCache() {
public void beforeNotify(Report report) {
report
.addToTab("device", "osArch", System.getProperty("os.arch"))
.addToTab("device", "runtimeName", System.getProperty("java.runtime.name"))
.addToTab("device", "runtimeVersion", System.getProperty("java.runtime.version"))
.addToTab("device", "locale", Locale.getDefault())
.setDeviceInfo("hostname", getHostnameValue())
.setDeviceInfo("osName", System.getProperty("os.name"))
Expand Down
2 changes: 1 addition & 1 deletion bugsnag/src/test/java/com/bugsnag/SessionPayloadTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public void testJsonSerialisation() {

JsonNode device = rootNode.get("device");
assertNotNull(device);
assertEquals(3, device.size());
assertEquals(4, device.size());
}

}
4 changes: 0 additions & 4 deletions features/meta_data.feature
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,13 @@ Scenario: Sends a handled exception which includes custom metadata added in a no
When I run spring boot "MetaDataScenario" with the defaults
Then I should receive a request
And the request is a valid for the error reporting API
And the event "metaData.device.springVersion" is not null
And the event "metaData.device.springBootVersion" is not null
And the event "metaData.Custom.foo" equals "Hello World!"

Scenario: Sends a handled exception which includes custom metadata added in a notify callback for plain Spring app
When I run plain Spring "MetaDataScenario" with the defaults
Then I should receive a request
And the request is a valid for the error reporting API
And the event "metaData.Custom.foo" equals "Hello World!"
And the event "metaData.device.springVersion" is not null
And the event "metaData.device.springBootVersion" is null

Scenario: Test logback appender with meta data in the config file
When I run "LogbackScenario" with logback config "meta_data_config.xml"
Expand Down
53 changes: 53 additions & 0 deletions features/runtime_versions.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
Feature: Runtime versions are included in all requests

### Errors

Scenario: Runtime versions included in Plain Java error
When I run "HandledExceptionScenario" with the defaults
Then I should receive a request
And the request is valid for the error reporting API
And the payload field "events.0.device.runtimeVersions.javaType" ends with "Runtime Environment"
And the payload field "events.0.device.runtimeVersions.javaVersion" matches the regex "(\d.)+"

Scenario: Runtime versions included in Spring Framework error
When I run plain Spring "HandledExceptionScenario" with the defaults
Then I should receive a request
And the request is valid for the error reporting API
And the payload field "events.0.device.runtimeVersions.javaType" ends with "Runtime Environment"
And the payload field "events.0.device.runtimeVersions.javaVersion" matches the regex "(\d.)+"
And the payload field "events.0.device.runtimeVersions.springFramework" matches the regex "(\d.)+"

Scenario: Runtime versions included in Spring Boot error
When I run spring boot "HandledExceptionScenario" with the defaults
Then I should receive a request
And the request is valid for the error reporting API
And the payload field "events.0.device.runtimeVersions.javaType" ends with "Runtime Environment"
And the payload field "events.0.device.runtimeVersions.javaVersion" matches the regex "(\d.)+"
And the payload field "events.0.device.runtimeVersions.springFramework" matches the regex "(\d.)+"
And the payload field "events.0.device.runtimeVersions.springBoot" matches the regex "(\d.)+"

### Sessions

Scenario: Runtime versions included in Plain Java session
When I run "ManualSessionScenario" with the defaults
Then I should receive a request
And the request is valid for the session tracking API
And the payload field "device.runtimeVersions.javaType" ends with "Runtime Environment"
And the payload field "device.runtimeVersions.javaVersion" matches the regex "(\d.)+"

Scenario: Runtime versions included in Spring Framework session
When I run plain Spring "ManualSessionScenario" with the defaults
Then I should receive a request
And the request is valid for the session tracking API
And the payload field "device.runtimeVersions.javaType" ends with "Runtime Environment"
And the payload field "device.runtimeVersions.javaVersion" matches the regex "(\d.)+"
And the payload field "device.runtimeVersions.springFramework" matches the regex "(\d.)+"

Scenario: Runtime versions included in Spring Boot session
When I run spring boot "ManualSessionScenario" with the defaults
Then I should receive a request
And the request is valid for the session tracking API
And the payload field "device.runtimeVersions.javaType" ends with "Runtime Environment"
And the payload field "device.runtimeVersions.javaVersion" matches the regex "(\d.)+"
And the payload field "device.runtimeVersions.springFramework" matches the regex "(\d.)+"
And the payload field "device.runtimeVersions.springBoot" matches the regex "(\d.)+"