Commit ff05fca9 by Johannes Edmeier

Update traces view and legacy converter to RC1

parent 6de90adf
...@@ -101,8 +101,8 @@ class Instance { ...@@ -101,8 +101,8 @@ class Instance {
}); });
} }
async fetchTrace() { async fetchHttptrace() {
return await axios.get(`instances/${this.id}/actuator/trace`, { return await axios.get(`instances/${this.id}/actuator/httptrace`, {
headers: {'Accept': actuatorMimeTypes} headers: {'Accept': actuatorMimeTypes}
}); });
} }
......
...@@ -20,13 +20,13 @@ import sbaInstancesAuditevents from './instances/auditevents'; ...@@ -20,13 +20,13 @@ import sbaInstancesAuditevents from './instances/auditevents';
import sbaInstancesDetails from './instances/details'; import sbaInstancesDetails from './instances/details';
import sbaInstancesEnv from './instances/env'; import sbaInstancesEnv from './instances/env';
import sbaInstancesFlyway from './instances/flyway'; import sbaInstancesFlyway from './instances/flyway';
import sbaInstancesTrace from './instances/httptrace';
import sbaInstancesLiquibase from './instances/liquibase'; import sbaInstancesLiquibase from './instances/liquibase';
import sbaInstancesLogfile from './instances/logfile'; import sbaInstancesLogfile from './instances/logfile';
import sbaInstancesLoggers from './instances/loggers'; import sbaInstancesLoggers from './instances/loggers';
import sbaInstancesSessions from './instances/sessions'; import sbaInstancesSessions from './instances/sessions';
import sbaInstancesShell from './instances/shell'; import sbaInstancesShell from './instances/shell';
import sbaInstancesThreaddump from './instances/threaddump'; import sbaInstancesThreaddump from './instances/threaddump';
import sbaInstancesTrace from './instances/trace';
import sbaJournal from './journal'; import sbaJournal from './journal';
...@@ -71,7 +71,7 @@ export default router => { ...@@ -71,7 +71,7 @@ export default router => {
}, { }, {
path: 'loggers', component: sbaInstancesLoggers, props: true, name: 'instance/loggers' path: 'loggers', component: sbaInstancesLoggers, props: true, name: 'instance/loggers'
}, { }, {
path: 'trace', component: sbaInstancesTrace, props: true, name: 'instance/trace' path: 'httptrace', component: sbaInstancesTrace, props: true, name: 'instance/httptrace'
}, { }, {
path: 'auditevents', component: sbaInstancesAuditevents, props: true, name: 'instance/auditevents' path: 'auditevents', component: sbaInstancesAuditevents, props: true, name: 'instance/auditevents'
}, { }, {
...@@ -114,10 +114,10 @@ export default router => { ...@@ -114,10 +114,10 @@ export default router => {
isActive: ({instance}) => instance.hasEndpoint('threaddump') isActive: ({instance}) => instance.hasEndpoint('threaddump')
}); });
views.register({ views.register({
name: 'instance/trace', name: 'instance/httptrace',
handle: 'Traces', handle: 'Http Traces',
order: 500, order: 500,
isActive: ({instance}) => instance.hasEndpoint('trace') isActive: ({instance}) => instance.hasEndpoint('httptrace')
}); });
views.register({ views.register({
name: 'instance/auditevents', name: 'instance/auditevents',
......
...@@ -180,8 +180,8 @@ ...@@ -180,8 +180,8 @@
}, },
}, },
methods: { methods: {
async fetchTrace() { async fetchHttptrace() {
const response = await this.instance.fetchTrace(); const response = await this.instance.fetchHttptrace();
const traces = response.data.traces.map(trace => new Trace(trace)).filter( const traces = response.data.traces.map(trace => new Trace(trace)).filter(
trace => trace.timestamp.isAfter(this.lastTimestamp) trace => trace.timestamp.isAfter(this.lastTimestamp)
); );
...@@ -197,7 +197,7 @@ ...@@ -197,7 +197,7 @@
vm.lastTimestamp = moment(0); vm.lastTimestamp = moment(0);
vm.error = null; vm.error = null;
return Observable.timer(0, 5000) return Observable.timer(0, 5000)
.concatMap(vm.fetchTrace) .concatMap(vm.fetchHttptrace)
.subscribe({ .subscribe({
next: traces => { next: traces => {
vm.hasLoaded = true; vm.hasLoaded = true;
......
...@@ -51,7 +51,8 @@ public class AdminServerProperties { ...@@ -51,7 +51,8 @@ public class AdminServerProperties {
* For Spring Boot 1.x applications SBA probes for the specified endpoints using an OPTIONS request. * For Spring Boot 1.x applications SBA probes for the specified endpoints using an OPTIONS request.
* If the path differs from the id you can specify this as id:path (e.g. health:ping). * If the path differs from the id you can specify this as id:path (e.g. health:ping).
*/ */
private String[] probedEndpoints = {"health", "env", "metrics", "trace", "threaddump:dump", "jolokia", "info", private String[] probedEndpoints = {"health", "env", "metrics", "httptrace:trace", "threaddump:dump", "jolokia",
"info",
"logfile", "refresh", "flyway", "liquibase", "heapdump", "loggers", "auditevents"}; "logfile", "refresh", "flyway", "liquibase", "heapdump", "loggers", "auditevents"};
public void setContextPath(String contextPath) { public void setContextPath(String contextPath) {
......
/* /*
* Copyright 2014-2017 the original author or authors. * Copyright 2014-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -24,7 +24,7 @@ public class Endpoint implements Serializable { ...@@ -24,7 +24,7 @@ public class Endpoint implements Serializable {
public static final String INFO = "info"; public static final String INFO = "info";
public static final String HEALTH = "health"; public static final String HEALTH = "health";
public static final String ENV = "env"; public static final String ENV = "env";
public static final String TRACE = "trace"; public static final String HTTPTRACE = "httptrace";
public static final String THREADDUMP = "threaddump"; public static final String THREADDUMP = "threaddump";
public static final String LIQUIBASE = "liquibase"; public static final String LIQUIBASE = "liquibase";
public static final String FLYWAY = "flyway"; public static final String FLYWAY = "flyway";
......
/* /*
* Copyright 2014-2017 the original author or authors. * Copyright 2014-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -46,7 +46,7 @@ public class InstanceWebClient { ...@@ -46,7 +46,7 @@ public class InstanceWebClient {
filters.add(InstanceFilterFunctions.rewriteEndpointUrl()); filters.add(InstanceFilterFunctions.rewriteEndpointUrl());
filters.add(InstanceFilterFunctions.convertLegacyEndpoint(LegacyEndpointConverters.health())); filters.add(InstanceFilterFunctions.convertLegacyEndpoint(LegacyEndpointConverters.health()));
filters.add(InstanceFilterFunctions.convertLegacyEndpoint(LegacyEndpointConverters.env())); filters.add(InstanceFilterFunctions.convertLegacyEndpoint(LegacyEndpointConverters.env()));
filters.add(InstanceFilterFunctions.convertLegacyEndpoint(LegacyEndpointConverters.trace())); filters.add(InstanceFilterFunctions.convertLegacyEndpoint(LegacyEndpointConverters.httptrace()));
filters.add(InstanceFilterFunctions.convertLegacyEndpoint(LegacyEndpointConverters.threaddump())); filters.add(InstanceFilterFunctions.convertLegacyEndpoint(LegacyEndpointConverters.threaddump()));
filters.add(InstanceFilterFunctions.convertLegacyEndpoint(LegacyEndpointConverters.liquibase())); filters.add(InstanceFilterFunctions.convertLegacyEndpoint(LegacyEndpointConverters.liquibase()));
filters.add(InstanceFilterFunctions.convertLegacyEndpoint(LegacyEndpointConverters.flyway())); filters.add(InstanceFilterFunctions.convertLegacyEndpoint(LegacyEndpointConverters.flyway()));
......
/* /*
* Copyright 2014-2017 the original author or authors. * Copyright 2014-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -20,6 +20,7 @@ import de.codecentric.boot.admin.server.domain.values.Endpoint; ...@@ -20,6 +20,7 @@ import de.codecentric.boot.admin.server.domain.values.Endpoint;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import java.time.Instant;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
...@@ -39,6 +40,7 @@ import com.fasterxml.jackson.databind.SerializationFeature; ...@@ -39,6 +40,7 @@ import com.fasterxml.jackson.databind.SerializationFeature;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
import static java.util.Collections.emptySet; import static java.util.Collections.emptySet;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap; import static java.util.Collections.singletonMap;
import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap; import static java.util.stream.Collectors.toMap;
...@@ -48,6 +50,8 @@ public class LegacyEndpointConverters { ...@@ -48,6 +50,8 @@ public class LegacyEndpointConverters {
}; };
private static final ParameterizedTypeReference<List<Object>> RESPONSE_TYPE_LIST = new ParameterizedTypeReference<List<Object>>() { private static final ParameterizedTypeReference<List<Object>> RESPONSE_TYPE_LIST = new ParameterizedTypeReference<List<Object>>() {
}; };
private static final ParameterizedTypeReference<List<Map<String, Object>>> RESPONSE_TYPE_LIST_MAP = new ParameterizedTypeReference<List<Map<String, Object>>>() {
};
private static final Jackson2JsonDecoder DECODER; private static final Jackson2JsonDecoder DECODER;
private static final Jackson2JsonEncoder ENCODER; private static final Jackson2JsonEncoder ENCODER;
...@@ -69,9 +73,9 @@ public class LegacyEndpointConverters { ...@@ -69,9 +73,9 @@ public class LegacyEndpointConverters {
convertUsing(RESPONSE_TYPE_MAP, RESPONSE_TYPE_MAP, LegacyEndpointConverters::convertEnv)); convertUsing(RESPONSE_TYPE_MAP, RESPONSE_TYPE_MAP, LegacyEndpointConverters::convertEnv));
} }
public static LegacyEndpointConverter trace() { public static LegacyEndpointConverter httptrace() {
return new LegacyEndpointConverter(Endpoint.TRACE, return new LegacyEndpointConverter(Endpoint.HTTPTRACE,
convertUsing(RESPONSE_TYPE_LIST, RESPONSE_TYPE_MAP, LegacyEndpointConverters::convertTrace)); convertUsing(RESPONSE_TYPE_LIST_MAP, RESPONSE_TYPE_MAP, LegacyEndpointConverters::convertHttptrace));
} }
public static LegacyEndpointConverter threaddump() { public static LegacyEndpointConverter threaddump() {
...@@ -81,12 +85,12 @@ public class LegacyEndpointConverters { ...@@ -81,12 +85,12 @@ public class LegacyEndpointConverters {
public static LegacyEndpointConverter liquibase() { public static LegacyEndpointConverter liquibase() {
return new LegacyEndpointConverter(Endpoint.LIQUIBASE, return new LegacyEndpointConverter(Endpoint.LIQUIBASE,
convertUsing(RESPONSE_TYPE_LIST, RESPONSE_TYPE_MAP, LegacyEndpointConverters::convertLiquibase)); convertUsing(RESPONSE_TYPE_LIST_MAP, RESPONSE_TYPE_MAP, LegacyEndpointConverters::convertLiquibase));
} }
public static LegacyEndpointConverter flyway() { public static LegacyEndpointConverter flyway() {
return new LegacyEndpointConverter(Endpoint.FLYWAY, return new LegacyEndpointConverter(Endpoint.FLYWAY,
convertUsing(RESPONSE_TYPE_LIST, RESPONSE_TYPE_MAP, LegacyEndpointConverters::convertFlyway)); convertUsing(RESPONSE_TYPE_LIST_MAP, RESPONSE_TYPE_MAP, LegacyEndpointConverters::convertFlyway));
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
...@@ -145,8 +149,52 @@ public class LegacyEndpointConverters { ...@@ -145,8 +149,52 @@ public class LegacyEndpointConverters {
return converted; return converted;
} }
private static Map<String, Object> convertTrace(List<Object> traces) { private static Map<String, Object> convertHttptrace(List<Map<String, Object>> traces) {
return singletonMap("traces", traces); return singletonMap("traces",
traces.stream().sequential().map(LegacyEndpointConverters::convertHttptrace).collect(toList()));
}
@SuppressWarnings("unchecked")
private static Map<String, Object> convertHttptrace(Map<String, Object> in) {
Map<String, Object> out = new LinkedHashMap<>();
out.put("timestamp", Instant.ofEpochMilli((Long) in.get("timestamp")));
Map<String, Object> in_info = (Map<String, Object>) in.get("info");
if (in_info != null) {
Map<String, Object> request = new LinkedHashMap<>();
request.put("method", in_info.get("method"));
request.put("uri", in_info.get("path"));
out.put("request", request);
Map<String, Object> response = new LinkedHashMap<>();
Map<String, Object> in_headers = (Map<String, Object>) in_info.get("headers");
if (in_headers != null) {
Map<String, Object> in_request_headers = (Map<String, Object>) in_headers.get("request");
if (in_request_headers != null) {
Map<String, Object> requestHeaders = new LinkedHashMap<>();
in_request_headers.forEach((k, v) -> requestHeaders.put(k, singletonList(v)));
request.put("headers", requestHeaders);
}
Map<String, Object> in_response_headers = (Map<String, Object>) in_headers.get("response");
if (in_response_headers != null) {
if (in_response_headers.get("status") instanceof String) {
response.put("status", Long.valueOf(in_response_headers.get("status").toString()));
}
Map<String, Object> responseHeaders = new LinkedHashMap<>();
in_response_headers.forEach((k, v) -> responseHeaders.put(k, singletonList(v)));
responseHeaders.remove("status");
response.put("headers", responseHeaders);
}
}
out.put("response", response);
if (in_info.get("timeTaken") instanceof String) {
out.put("timeTaken", Long.valueOf(in_info.get("timeTaken").toString()));
}
}
return out;
} }
private static Map<String, Object> convertThreaddump(List<Object> threads) { private static Map<String, Object> convertThreaddump(List<Object> threads) {
...@@ -154,10 +202,8 @@ public class LegacyEndpointConverters { ...@@ -154,10 +202,8 @@ public class LegacyEndpointConverters {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private static Map<String, Object> convertLiquibase(List<Object> reports) { private static Map<String, Object> convertLiquibase(List<Map<String, Object>> reports) {
return reports.stream() return reports.stream().sequential()
.filter(Map.class::isInstance)
.map(r -> (Map<String, Object>) r)
.collect(toMap(r -> (String) r.get("name"), r -> singletonMap("changeSets", .collect(toMap(r -> (String) r.get("name"), r -> singletonMap("changeSets",
LegacyEndpointConverters.convertLiquibaseChangesets( LegacyEndpointConverters.convertLiquibaseChangesets(
(List<Map<String, Object>>) r.get("changeLogs"))))); (List<Map<String, Object>>) r.get("changeLogs")))));
...@@ -190,10 +236,8 @@ public class LegacyEndpointConverters { ...@@ -190,10 +236,8 @@ public class LegacyEndpointConverters {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private static Map<String, Object> convertFlyway(List<Object> reports) { private static Map<String, Object> convertFlyway(List<Map<String, Object>> reports) {
return reports.stream() return reports.stream().sequential()
.filter(Map.class::isInstance)
.map(r -> (Map<String, Object>) r)
.collect(toMap(r -> (String) r.get("name"), r -> singletonMap("migrations", .collect(toMap(r -> (String) r.get("name"), r -> singletonMap("migrations",
LegacyEndpointConverters.convertFlywayMigrations( LegacyEndpointConverters.convertFlywayMigrations(
(List<Map<String, Object>>) r.get("migrations"))))); (List<Map<String, Object>>) r.get("migrations")))));
......
...@@ -71,14 +71,14 @@ public class LegacyEndpointConvertersTest { ...@@ -71,14 +71,14 @@ public class LegacyEndpointConvertersTest {
@Test @Test
public void should_convert_trace() { public void should_convert_trace() {
LegacyEndpointConverter converter = LegacyEndpointConverters.trace(); LegacyEndpointConverter converter = LegacyEndpointConverters.httptrace();
assertThat(converter.canConvert("trace")).isTrue(); assertThat(converter.canConvert("httptrace")).isTrue();
assertThat(converter.canConvert("foo")).isFalse(); assertThat(converter.canConvert("foo")).isFalse();
Flux<DataBuffer> legacyInput = this.read("trace-legacy.json"); Flux<DataBuffer> legacyInput = this.read("httptrace-legacy.json");
Flux<Object> converted = converter.convert(legacyInput).transform(this::unmarshal); Flux<Object> converted = converter.convert(legacyInput).transform(this::unmarshal);
Flux<Object> expected = this.read("trace-expected.json").transform(this::unmarshal); Flux<Object> expected = this.read("httptrace-expected.json").transform(this::unmarshal);
StepVerifier.create(Flux.zip(converted, expected)) StepVerifier.create(Flux.zip(converted, expected))
.assertNext(t -> assertThat(t.getT1()).isEqualTo(t.getT2())) .assertNext(t -> assertThat(t.getT1()).isEqualTo(t.getT2()))
......
{
"traces": [
{
"timestamp": "2018-02-04T21:58:53.427Z",
"request": {
"method": "HEAD",
"uri": "/actuator/liquibase",
"headers": {
"pragma": [
"no-cache"
],
"cache-control": [
"no-cache"
],
"accept": [
"application/json, text/plain, */*"
],
"user-agent": [
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
],
"accept-language": [
"de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7"
],
"accept-encoding": [
"gzip"
],
"host": [
"172.17.0.17:8080"
],
"connection": [
"Keep-Alive"
]
}
},
"response": {
"status": 404,
"headers": {
"X-Application-Context": [
"spring-application"
]
}
},
"timeTaken": 2
},
{
"timestamp": "2018-02-04T21:58:45.290Z",
"request": {
"method": "GET",
"uri": "",
"headers": {
"accept": [
"application/json, text/plain, */*"
],
"user-agent": [
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
],
"accept-language": [
"de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7"
],
"accept-encoding": [
"gzip, deflate, br"
],
"x-requested-with": [
"XMLHttpRequest"
]
}
},
"response": {
"status": 200,
"headers": {
"X-Application-Context": [
"spring-application"
],
"Content-Type": [
"application/json;charset=UTF-8"
],
"Transfer-Encoding": [
"chunked"
],
"Date": [
"Sun, 04 Feb 2018 21:58:44 GMT"
]
}
}
}
]
}
\ No newline at end of file
[
{
"timestamp": 1517781533427,
"info": {
"method": "HEAD",
"path": "/actuator/liquibase",
"headers": {
"request": {
"pragma": "no-cache",
"cache-control": "no-cache",
"accept": "application/json, text/plain, */*",
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36",
"accept-language": "de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7",
"accept-encoding": "gzip",
"host": "172.17.0.17:8080",
"connection": "Keep-Alive"
},
"response": {
"X-Application-Context": "spring-application",
"status": "404"
}
},
"timeTaken": "2"
}
},
{
"timestamp": 1517781525290,
"info": {
"method": "GET",
"path": "",
"headers": {
"request": {
"accept": "application/json, text/plain, */*",
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36",
"accept-language": "de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7",
"accept-encoding": "gzip, deflate, br",
"x-requested-with": "XMLHttpRequest"
},
"response": {
"X-Application-Context": "spring-application",
"Content-Type": "application/json;charset=UTF-8",
"Transfer-Encoding": "chunked",
"Date": "Sun, 04 Feb 2018 21:58:44 GMT",
"status": "200"
}
}
}
}
]
\ No newline at end of file
{
"traces": [
{
"timestamp": "15610000",
"info": {
"status": 200
}
},
{
"timestamp": "15610001",
"info": {
"status": 200
}
}
]
}
\ No newline at end of file
[
{
"timestamp": "15610000",
"info": {
"status": 200
}
},
{
"timestamp": "15610001",
"info": {
"status": 200
}
}
]
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment