Skip to content

Commit

Permalink
Add ability to show stack traces in danger alerts (#215)
Browse files Browse the repository at this point in the history
* Add ability to show stack traces in danger alerts

* (Slightly) improve error handling
  • Loading branch information
Crim authored Jun 8, 2020
1 parent fb860ca commit 4870467
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@

package org.sourcelab.kafka.webview.ui.controller.configuration.cluster;

import org.apache.kafka.common.KafkaException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sourcelab.kafka.webview.ui.controller.BaseController;
Expand Down Expand Up @@ -421,12 +420,14 @@ public String testCluster(@PathVariable final Long id, final RedirectAttributes
redirectAttributes.addFlashAttribute("FlashMessage", FlashMessage.newSuccess("Cluster configuration is valid!"));
}
} catch (final Exception e) {
String reason = e.getMessage();
if (e instanceof KafkaException && e.getCause() != null) {
reason = e.getCause().getMessage();
}
// Collect all reasons.
final String reason = e.getMessage();

// Set error msg
redirectAttributes.addFlashAttribute("FlashMessage", FlashMessage.newDanger("Error connecting to cluster: " + reason));
redirectAttributes.addFlashAttribute(
"FlashMessage",
FlashMessage.newDanger("Error connecting to cluster: " + reason, e)
);

// Mark as invalid
cluster.setValid(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import org.apache.kafka.clients.admin.TopicListing;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.clients.consumer.OffsetAndMetadata;
import org.apache.kafka.common.KafkaException;
import org.apache.kafka.common.Node;
import org.apache.kafka.common.TopicPartitionInfo;
import org.apache.kafka.common.config.ConfigResource;
Expand Down Expand Up @@ -114,7 +115,9 @@ public TopicList getAvailableTopics() {
);
}
return new TopicList(topicListings);
} catch (InterruptedException | ExecutionException e) {
} catch (final ExecutionException e) {
throw handleExecutionException(e);
} catch (final InterruptedException e) {
// TODO Handle
throw new RuntimeException(e.getMessage(), e);
}
Expand All @@ -128,12 +131,13 @@ public NodeList getClusterNodes() {

try {
final Collection<Node> nodes = adminClient.describeCluster().nodes().get();
for (final Node node: nodes) {
for (final Node node : nodes) {
nodeDetails.add(new NodeDetails(node.id(), node.host(), node.port(), node.rack()));
}
return new NodeList(nodeDetails);
} catch (InterruptedException | ExecutionException e) {
// TODO Handle
} catch (final ExecutionException e) {
throw handleExecutionException(e);
} catch (final InterruptedException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
Expand Down Expand Up @@ -201,7 +205,9 @@ public Map<String, TopicDetails> getTopicDetails(final Collection<String> topics
}
// Return it
return results;
} catch (final InterruptedException | ExecutionException exception) {
} catch (final ExecutionException e) {
throw handleExecutionException(e);
} catch (final InterruptedException exception) {
// TODO Handle this
throw new RuntimeException(exception.getMessage(), exception);
}
Expand Down Expand Up @@ -252,7 +258,9 @@ public boolean createTopic(final CreateTopic createTopic) {

// return true?
return true;
} catch (final InterruptedException | ExecutionException exception) {
} catch (final ExecutionException e) {
throw handleExecutionException(e);
} catch (final InterruptedException exception) {
// TODO Handle this
throw new RuntimeException(exception.getMessage(), exception);
}
Expand Down Expand Up @@ -287,7 +295,9 @@ public TopicConfig alterTopicConfig(final String topic, final Map<String, String

// Lets return updated topic details
return getTopicConfig(topic);
} catch (final InterruptedException | ExecutionException exception) {
} catch (final ExecutionException e) {
throw handleExecutionException(e);
} catch (final InterruptedException exception) {
// TODO Handle this
throw new RuntimeException(exception.getMessage(), exception);
}
Expand All @@ -307,7 +317,9 @@ public boolean removeTopic(final String topic) {

// return true?
return true;
} catch (final InterruptedException | ExecutionException exception) {
} catch (final ExecutionException e) {
throw handleExecutionException(e);
} catch (final InterruptedException exception) {
// TODO Handle this
throw new RuntimeException(exception.getMessage(), exception);
}
Expand Down Expand Up @@ -340,8 +352,9 @@ public List<ConsumerGroupIdentifier> listConsumers() {

// return immutable list.
return Collections.unmodifiableList(consumerIds);

} catch (final InterruptedException | ExecutionException e) {
} catch (final ExecutionException e) {
throw handleExecutionException(e);
} catch (final InterruptedException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
Expand All @@ -358,7 +371,9 @@ public boolean removeConsumerGroup(final String id) {
try {
request.all().get();
return true;
} catch (InterruptedException | ExecutionException e) {
} catch (final ExecutionException e) {
throw handleExecutionException(e);
} catch (InterruptedException e) {
// TODO Handle this
throw new RuntimeException(e.getMessage(), e);
}
Expand Down Expand Up @@ -444,7 +459,9 @@ public List<ConsumerGroupDetails> getConsumerGroupDetails(final List<String> con

// Return immutable list.
return Collections.unmodifiableList(consumerGroupDetails);
} catch (final InterruptedException | ExecutionException e) {
} catch (final ExecutionException e) {
throw handleExecutionException(e);
} catch (final InterruptedException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
Expand Down Expand Up @@ -476,7 +493,9 @@ public ConsumerGroupOffsets getConsumerGroupOffsets(final String consumerGroupId
}

return builder.build();
} catch (final InterruptedException | ExecutionException e) {
} catch (final ExecutionException e) {
throw handleExecutionException(e);
} catch (final InterruptedException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
Expand Down Expand Up @@ -573,12 +592,21 @@ private List<ConfigItem> describeResource(final ConfigResource configResource) {
);
}
return configItems;
} catch (InterruptedException | ExecutionException e) {
} catch (final ExecutionException e) {
throw handleExecutionException(e);
} catch (InterruptedException e) {
// TODO Handle this
throw new RuntimeException(e.getMessage(), e);
}
}

private RuntimeException handleExecutionException(final ExecutionException e) {
if (e.getCause() != null && e.getCause() instanceof RuntimeException) {
return (RuntimeException) e.getCause();
}
return new RuntimeException(e.getMessage(), e);
}

/**
* Close out the Client.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

package org.sourcelab.kafka.webview.ui.manager.kafka.dto;

import net.bytebuddy.implementation.bytecode.Throw;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
Expand Down Expand Up @@ -77,7 +79,7 @@ public String toString() {
* @param exception exception.
* @return Array of ApiErrorCauses.
*/
public static ApiErrorCause[] buildCauseList(final Exception exception) {
public static ApiErrorCause[] buildCauseList(final Throwable exception) {
if (exception == null) {
return new ApiErrorCause[0];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,30 @@

package org.sourcelab.kafka.webview.ui.manager.ui;

import org.sourcelab.kafka.webview.ui.manager.kafka.dto.ApiErrorCause;
import org.sourcelab.kafka.webview.ui.manager.kafka.dto.ApiErrorResponse;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
* Represents an Alert Message.
*/
public class FlashMessage {
private final String type;
private final String message;
private final List<String> details;

private FlashMessage(final String type, final String message) {
this.type = type;
this.message = message;
this(type, message, Collections.emptyList());
}

private FlashMessage(final String type, final String message, final List<String> details) {
this.type = Objects.requireNonNull(type);
this.message = Objects.requireNonNull(message);
this.details = Objects.requireNonNull(Collections.unmodifiableList(new ArrayList<>(details)));
}

public String getType() {
Expand All @@ -60,6 +74,14 @@ public boolean isDanger() {
return "danger".equals(getType());
}

public boolean hasDetails() {
return !details.isEmpty();
}

public List<String> getDetails() {
return details;
}

public static FlashMessage newSuccess(final String message) {
return new FlashMessage("success", message);
}
Expand All @@ -76,6 +98,38 @@ public static FlashMessage newDanger(final String message) {
return new FlashMessage("danger", message);
}

/**
* Create a new Danger alert with stack trace.
* @param message Message to display.
* @param details Additional details about the error.
* @return FlashMessage instance.
*/
public static FlashMessage newDanger(final String message, final List<String> details) {
return new FlashMessage("danger", message, details);
}

/**
* Create a new Danger alert with stack trace.
* @param message Message to display.
* @param cause Underlying exception.
* @return FlashMessage instance.
*/
public static FlashMessage newDanger(final String message, final Throwable cause) {
final List<String> reasons = convertExceptionToDetails(cause);

return new FlashMessage("danger", message, reasons);
}

private static List<String> convertExceptionToDetails(final Throwable throwable) {
final ApiErrorCause[] causes = ApiErrorResponse.buildCauseList(throwable);
final List<String> reasons = new ArrayList<>();

for (final ApiErrorCause cause : causes) {
reasons.add(cause.getType() + " thrown at " + cause.getMethod() + " -> " + cause.getMessage());
}
return reasons;
}

@Override
public String toString() {
return "FlashMessage{"
Expand Down
15 changes: 13 additions & 2 deletions kafka-webview-ui/src/main/resources/templates/fragments/alert.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,20 @@
<body>

<!-- Handles showing Alerts -->
<div th:if="${FlashMessage != null}" class="alert alert-dismissable" th:fragment="alert (message)" th:classappend="'alert-' + ${message.getType()}">
<div th:if="${message != null}" class="alert alert-dismissable" th:fragment="alert (message)" th:classappend="'alert-' + ${message.getType()}">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
<span th:text="${message.getMessage()}"></span>
<span th:text="${message.getMessage()}">
</span>
<span th:if="${message.hasDetails()}">
(<a data-toggle="collapse" href="#stackTrace" role="button" aria-expanded="false" aria-controls="stackTrace">show more</a>)
</span>
<div th:if="${message.hasDetails()}" class="collapse" id="stackTrace" >
<ol>
<li th:each="detail : ${message.getDetails()}" th:text="${detail}">
</li>
</ol>
</div>

</div>

</body>
Expand Down

0 comments on commit 4870467

Please sign in to comment.