在控制器建议中获取控制器名称和 java 服务路径
Posted
技术标签:
【中文标题】在控制器建议中获取控制器名称和 java 服务路径【英文标题】:Get controller name and java service path in controller advice 【发布时间】:2020-05-06 13:19:08 【问题描述】:大家好,我已经在我的 Spring Boot 应用程序中创建了一个全局异常处理程序,并将发生在 AWS cloudwatch 中的异常写入下面的代码工作正常我能够在 cloudwatch 中编写异常,但挑战是我无法获得 Restcontroller 名称以及发生特定异常的服务路径。
示例 java 服务
@GetMapping(value = "DynamoDb/deleteTable")
public String deleteTable(@RequestParam String TableName) throws InterruptedException
Table table = dynamoDB.getTable(TableName);
try
table.delete();
table.waitForDelete();
catch (Exception e)
throw e;
return "Success";
当发生异常时,它会将控制权转移到 controlleradvice 全局异常处理程序
这是我的代码
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.cloudwatchlogs.CloudWatchLogsClient;
import software.amazon.awssdk.services.cloudwatchlogs.model.DescribeLogStreamsRequest;
import software.amazon.awssdk.services.cloudwatchlogs.model.DescribeLogStreamsResponse;
import software.amazon.awssdk.services.cloudwatchlogs.model.InputLogEvent;
import software.amazon.awssdk.services.cloudwatchlogs.model.PutLogEventsRequest;
import java.util.Arrays;
@ControllerAdvice
public class ExceptionControllerAdvice
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> exceptionHandler(Exception ex)
ErrorResponse error = new ErrorResponse();
error.setErrorCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
error.setMessage(ex.getMessage());
error.setController(ex.getMessage());
error.setService(ex.getMessage());
error.setTimestamp(System.currentTimeMillis());
PutLogEvents(error);
return new ResponseEntity<ErrorResponse>(error, HttpStatus.OK);
public static void PutLogEvents(ErrorResponse Er)
String regionId = "us-east-1";
String logGroupName = "xxxxxxx";
String logStreamName = "xxxxxxx";
CloudWatchLogsClient logsClient = CloudWatchLogsClient.builder().region(Region.of(regionId)).build();
// A sequence token is required to put a log event in an existing stream.
// Look up the stream to find its sequence token.
String sequenceToken = getNextSequenceToken(logsClient, logGroupName, logStreamName);
// Build a JSON log using the EmbeddedMetricFormat.
String message = "[" +
" \"Timestamp\": " + Er.getTimestamp() + "," +
" \"ErrorCode\": " + Er.getErrorCode() + "," +
" \"ControllerName\": " + Er.getErrorCode() + "," +
" \"ServiceName\": " + Er.getErrorCode() + "," +
" \"ErrorMsg\": " + Er.getErrorCode() + "" +
"]";
InputLogEvent inputLogEvent = InputLogEvent.builder()
.message(message)
.timestamp(Er.getTimestamp())
.build();
// Specify the request parameters.
PutLogEventsRequest putLogEventsRequest = PutLogEventsRequest.builder()
.logEvents(Arrays.asList(inputLogEvent))
.logGroupName(logGroupName)
.logStreamName(logStreamName)
// Sequence token is required so that the log can be written to the
// latest location in the stream.
.sequenceToken(sequenceToken)
.build();
logsClient.putLogEvents(putLogEventsRequest);
private static String getNextSequenceToken(CloudWatchLogsClient logsClient, String logGroupName, String logStreamName)
DescribeLogStreamsRequest logStreamRequest = DescribeLogStreamsRequest.builder()
.logGroupName(logGroupName)
.logStreamNamePrefix(logStreamName)
.build();
DescribeLogStreamsResponse describeLogStreamsResponse = logsClient.describeLogStreams(logStreamRequest);
// Assume that a single stream is returned since a specific stream name was
// specified in the previous request.
return describeLogStreamsResponse.logStreams().get(0).uploadSequenceToken();
Errorresponse.class
public class ErrorResponse
private int errorCode;
private String message;
private String Controller;
private String Service;
private String ProjectName;
private long Timestamp;
public ErrorResponse(int errorCode, String message, String controller, String service, String projectName, long timestamp)
this.errorCode = errorCode;
this.message = message;
Controller = controller;
Service = service;
ProjectName = projectName;
Timestamp = timestamp;
public ErrorResponse()
@Override
public String toString()
return "ErrorResponse" +
"errorCode=" + errorCode +
", message='" + message + '\'' +
", Controller='" + Controller + '\'' +
", Service='" + Service + '\'' +
", ProjectName='" + ProjectName + '\'' +
", Timestamp=" + Timestamp +
'';
public int getErrorCode()
return errorCode;
public void setErrorCode(int errorCode)
this.errorCode = errorCode;
public String getMessage()
return message;
public void setMessage(String message)
this.message = message;
public String getController()
return Controller;
public void setController(String controller)
Controller = controller;
public String getService()
return Service;
public void setService(String service)
Service = service;
public String getProjectName()
return ProjectName;
public void setProjectName(String projectName)
ProjectName = projectName;
public long getTimestamp()
return Timestamp;
public void setTimestamp(long timestamp)
Timestamp = timestamp;
谁能帮助我如何在全局异常处理程序中获取 Restcontroller 名称和服务路径?
【问题讨论】:
您需要对我的答案发表评论,而不是尝试对其进行编辑。 添加HandlerMethod
类型的方法参数以获取方法名称和封闭控制器。 @ExceptionHandler
注解的方法可以使用多种不同类型的参数。
通过使用代码 Class controllerClass = handlerMethod.getMethod().getDeclaringClass(); 我可以获得控制器名称
知道如何使用处理程序方法获取 java 服务路径或方法名称?
【参考方案1】:
大家好,感谢大家使用下面的代码,我能够得到客户建议的结果。希望这可以帮助一些人。谢谢
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.method.HandlerMethod;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.cloudwatchlogs.CloudWatchLogsClient;
import software.amazon.awssdk.services.cloudwatchlogs.model.DescribeLogStreamsRequest;
import software.amazon.awssdk.services.cloudwatchlogs.model.DescribeLogStreamsResponse;
import software.amazon.awssdk.services.cloudwatchlogs.model.InputLogEvent;
import software.amazon.awssdk.services.cloudwatchlogs.model.PutLogEventsRequest;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Arrays;
@ControllerAdvice
public class ExceptionControllerAdvice
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
@Value("$application.name")
private String applicationName;
@Value("$aws.logGroupName")
private String logGroupName;
@Value("$aws.logStreamName")
private String logStreamName;
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> exceptionHandler(Exception ex, HandlerMethod handlerMethod, HttpServletRequest request) throws JsonProcessingException
Class ControllerName = handlerMethod.getMethod().getDeclaringClass();
String MethodName = handlerMethod.getMethod().getName();
ErrorResponse error = new ErrorResponse();
error.setErrorCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
error.setErrorMessage(ex.getMessage());
error.setControllerName(ControllerName.toString());
error.setServiceName(MethodName.toString());
error.setTimeStamp(sdf.format(System.currentTimeMillis()));
error.setProjectName(applicationName);
error.setServicePath(request.getRequestURL().toString());
PutLogEvents(error);
return new ResponseEntity<ErrorResponse>(error, HttpStatus.OK);
public void PutLogEvents(ErrorResponse Er) throws JsonProcessingException
String regionId = "xxxxx";
String logGroupName = "xxxxx";
String logStreamName = "xxxxx";
CloudWatchLogsClient logsClient = CloudWatchLogsClient.builder().region(Region.of(regionId)).build();
// A sequence token is required to put a log event in an existing stream.
// Look up the stream to find its sequence token.
String sequenceToken = getNextSequenceToken(logsClient, logGroupName, logStreamName);
// Build a JSON log using the EmbeddedMetricFormat.
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
String json = ow.writeValueAsString(Er);
String message =json;
InputLogEvent inputLogEvent = InputLogEvent.builder()
.message(message)
.timestamp(System.currentTimeMillis())
.build();
// Specify the request parameters.
PutLogEventsRequest putLogEventsRequest = PutLogEventsRequest.builder()
.logEvents(Arrays.asList(inputLogEvent))
.logGroupName(logGroupName)
.logStreamName(logStreamName)
// Sequence token is required so that the log can be written to the
// latest location in the stream.
.sequenceToken(sequenceToken)
.build();
logsClient.putLogEvents(putLogEventsRequest);
private static String getNextSequenceToken(CloudWatchLogsClient logsClient, String logGroupName, String logStreamName)
DescribeLogStreamsRequest logStreamRequest = DescribeLogStreamsRequest.builder()
.logGroupName(logGroupName)
.logStreamNamePrefix(logStreamName)
.build();
DescribeLogStreamsResponse describeLogStreamsResponse = logsClient.describeLogStreams(logStreamRequest);
// Assume that a single stream is returned since a specific stream name was
// specified in the previous request.
return describeLogStreamsResponse.logStreams().get(0).uploadSequenceToken();
结果应该是这样的
"errorMessage": "Table already exists: ProductFgh (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ResourceInUseException; Request ID: 6S14VS0E6ESUMG55DL937IC42JVV4KQNSO5AEMVJF66Q9ASUAAJG)",
"timeStamp": "2020-Jan-22 11:53:58",
"errorCode": 500,
"projectName": "DynamoDB",
"servicePath": "http://localhost:8090/DynamoDb/createTable",
"controllerName": "class com.example.DynamoDB.DynamoDBController",
"serviceName": "createExampleTable"
到目前为止,我已经通过上面的代码实现了这一点,如果有更好的方法可以告诉我。谢谢大家
【讨论】:
【参考方案2】:您可以通过以下方式获取引发异常的类名:
ex.getStackTrace()[0].getClassName();
【讨论】:
我得到这样的结果 com.amazonaws.http.AmazonHttpClient$RequestExecutor以上是关于在控制器建议中获取控制器名称和 java 服务路径的主要内容,如果未能解决你的问题,请参考以下文章
使用Route属性在Controller方法中获取控制器和动作名称