Amazon Cloudwatch Logs - PutLogEvents 请求 - 给定的 sequenceToken 无效
Amazon Cloud Watch Log - PutLogEventsRequest - The given sequenceToken is invalid
我正在使用 Amazon Cloud Watch 服务为我的应用程序构建一个小型日志跟踪器。这个想法不是跟踪文件上的日志输出,而是使用来自 aws 控制台的搜索引擎来查找日志信息。
我正在使用:
- Eclipse 为 IDE
- Java 8
- 依赖项:aws-java-sdk-core / aws-java-sdk-cloudwatch V 1.10.49
另一方面,我有以下 AWS 配置:
- 访问和私钥
- 地区:加利福尼亚州
- 日志组:demo1
- 日志流:stream1
我正在编写以下代码来进行简单的功能测试:
package com.test.pe.cloudwatch;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.regions.Region;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.logs.AWSLogsClient;
import com.amazonaws.services.logs.model.InputLogEvent;
import com.amazonaws.services.logs.model.PutLogEventsRequest;
import com.amazonaws.services.logs.model.PutLogEventsResult;
import com.test.pe.base.CredentialBuilder;
public class RegisterLog {
private static String LOG_GROUP = "demo1";
private static String LOG_STREAM = "stream1";
public static void main(String[] args) throws ParseException {
// building my credential and calendar instances
AWSCredentials credential = CredentialBuilder.getCredential();
Calendar calendar = Calendar.getInstance();
// building a cloud watch log client
AWSLogsClient cloudWatchlog = new AWSLogsClient(credential);
cloudWatchlog.setRegion(Region.getRegion(Regions.US_WEST_1));
// building a put request log
PutLogEventsRequest request = new PutLogEventsRequest();
request.setLogGroupName(LOG_GROUP);
request.setLogStreamName(LOG_STREAM);
// building my log event
InputLogEvent log = new InputLogEvent();
log.setMessage("Some message for a test");
log.setTimestamp(calendar.getTimeInMillis());
// building the array list log event
ArrayList<InputLogEvent> logEvents = new ArrayList<InputLogEvent>();
logEvents.add(log);
// setting the error array list
request.setLogEvents(logEvents);
// make the request
cloudWatchlog.putLogEvents(request);
System.out.println("done!");
}
}
当我运行第一次对码时一切正常,消息保存成功
但是,当我第二次执行代码时,出现以下异常:
Exception in thread "main" com.amazonaws.services.logs.model.InvalidSequenceTokenException: The given sequenceToken is invalid. The next expected sequenceToken is: xxxxxxxxxxxxxxxxxxxxxxxxxxx (Service: AWSLogs; Status Code: 400; Error Code: InvalidSequenceTokenException; Request ID: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)
at com.amazonaws.http.AmazonHttpClient.handleErrorResponse(AmazonHttpClient.java:1389)
XXXXXXXXXXX : 是亚马逊生成的令牌代码。
阅读亚马逊文档,我发现了以下信息:
请求语法:
{
"LogEvents": [
{
"Message": "string",
"Timestamp": number
}
],
"LogGroupName": "string",
"LogStreamName": "string",
"SequenceToken": "string"
}
SequenceToken
A string token that must be obtained from the response of the previous PutLogEvents request.
Type: String
Length constraints: Minimum length of 1.
Required: No
amazon documentation about cloud watch log REST API
我决定在我的代码中硬编码序列标记,如下所示:
request.setSequenceToken("58523.......");
它工作正常。我只是为了测试才做的。
最后,我发现获取序列标记的唯一方法是。
PutLogEventsResult response = cloudWatchlog.putLogEvents(request);
String token = response.getNextSequenceToken();
如何在发出请求之前验证并获取序列码?我在文档中找不到它。
您通常会在调用 putLogEvents (getNextSequenceToken) 时获得 nextToken。如果有不止一个生产者向流推送,他们在竞争并且一次只有一个可以推送(即:如果你得到一个令牌而其他人推送它会使你的令牌无效)。
如果发生这种情况,您需要描述流并获取新令牌:http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_DescribeLogStreams.html
所以模式是:
1) 如果您没有有效令牌或根本没有令牌(您才刚刚开始),请描述流以找出令牌。
2)使用您获得的令牌进行推送。如果推送成功更新令牌
3)若推送不成功,则转1),获取新的token,重试。如果有多个生产者,您可能需要尝试多次(即循环)。
我遇到了同样的问题并使用以下方法解决了它:
String token = logStream.getUploadSequenceToken();
完整源码:
public CloudWatchHandler(String logGroupName, String logStreamName) {
credentials = new DefaultAWSCredentialsProviderChain().getCredentials();
awsLogsClient = new AWSLogsClient(credentials);
awsLogsClient.setRegion(Region.getRegion(Regions.US_WEST_2));
this.logGroupName = logGroupName;
this.logStreamName = logStreamName;
logStreamsRequest = new DescribeLogStreamsRequest(logGroupName);
logStreamList = new ArrayList<LogStream>();
putLogEventsRequest = new PutLogEventsRequest();
putLogEventsResult = new PutLogEventsResult();
}
public void log(String message) {
logEvents = new ArrayList<InputLogEvent>();
log = new InputLogEvent();
calendar = Calendar.getInstance();
log.setTimestamp(calendar.getTimeInMillis());
log.setMessage(message);
logEvents.add(log);
logStreamsRequest.withLimit(5);
logStreamList= awsLogsClient.describeLogStreams(logStreamsRequest).getLogStreams();
for (LogStream logStream: logStreamList) {
if (logStream.getLogStreamName().equals(logStreamName))
token = logStream.getUploadSequenceToken();
}
if (token!=null) {
putLogEventsRequest.setLogGroupName(logGroupName);
putLogEventsRequest.setLogStreamName(logStreamName);
putLogEventsRequest.setLogEvents(logEvents);
putLogEventsRequest.setSequenceToken(token);
putLogEventsResult = awsLogsClient.putLogEvents(putLogEventsRequest);
}
}
我在使用当前发布的代码时仍然遇到了一些问题,所以我将添加我的工作解决方案来帮助解决问题:
"logStream.getLogStreamName()"
返回的不仅仅是流的名称,所以我通过使用 DescribeLogStreamsRequest().withLogGroupName("myCrAzYLogGroup");
获得了流
//creds
String awsAccessKey = System.getProperty("AWS_ACCESS_KEY_ID");
String awsSecretKey = System.getProperty("AWS_SECRET_ACCESS_KEY");
Calendar calendar = Calendar.getInstance();
AWSCredentials credential = new BasicAWSCredentials(awsAccessKey, awsSecretKey);
AWSLogsClient awsLogsClient = new AWSLogsClient(credential);
awsLogsClient.setRegion(Region.getRegion(Regions.US_WEST_2));
//only difference in my code (i wanted to point out) is the use of BasicAWSCredentials
//AWSCredentials credential = CredentialBuilder.getCredential();
//AWSLogsClient cloudWatchlog = new AWSLogsClient(credential);
PutLogEventsRequest putLogEventsRequest = new PutLogEventsRequest();
putLogEventsRequest.setLogGroupName("myCrAzYLogGroup");
putLogEventsRequest.setLogStreamName("myCrAzYLogStream");
String token = null;
//here's mainly what I changed
DescribeLogStreamsRequest logStreamsRequest = new DescribeLogStreamsRequest().withLogGroupName("myCrAzYLogGroup");
List<LogStream> logStreamList = new ArrayList<LogStream>();
logStreamList= awsLogsClient.describeLogStreams(logStreamsRequest).getLogStreams();
//the answer to this question (get the token and use it)
//keep in mind I'm not comparing because I only have one stream
//again this is just to help get started/trouble shoot with a simplified setup
for (LogStream logStream: logStreamList) {
token = logStream.getUploadSequenceToken();
}
if(token != null)
{
putLogEventsRequest.setSequenceToken(token);
}
InputLogEvent testEvent = new InputLogEvent();
testEvent.setMessage("let's test this log!");
testEvent.setTimestamp(calendar.getTimeInMillis());
ArrayList<InputLogEvent> logEvents = new ArrayList<InputLogEvent>();
logEvents.add(testEvent);
putLogEventsRequest.setLogEvents(logEvents);
PutLogEventsResult putLogEventsResult = new PutLogEventsResult();
//this will return the next token if you want to hold onto it
putLogEventsResult = awsLogsClient.putLogEvents(putLogEventsRequest);
我正在使用 Amazon Cloud Watch 服务为我的应用程序构建一个小型日志跟踪器。这个想法不是跟踪文件上的日志输出,而是使用来自 aws 控制台的搜索引擎来查找日志信息。
我正在使用:
- Eclipse 为 IDE
- Java 8
- 依赖项:aws-java-sdk-core / aws-java-sdk-cloudwatch V 1.10.49
另一方面,我有以下 AWS 配置:
- 访问和私钥
- 地区:加利福尼亚州
- 日志组:demo1
- 日志流:stream1
我正在编写以下代码来进行简单的功能测试:
package com.test.pe.cloudwatch;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.regions.Region;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.logs.AWSLogsClient;
import com.amazonaws.services.logs.model.InputLogEvent;
import com.amazonaws.services.logs.model.PutLogEventsRequest;
import com.amazonaws.services.logs.model.PutLogEventsResult;
import com.test.pe.base.CredentialBuilder;
public class RegisterLog {
private static String LOG_GROUP = "demo1";
private static String LOG_STREAM = "stream1";
public static void main(String[] args) throws ParseException {
// building my credential and calendar instances
AWSCredentials credential = CredentialBuilder.getCredential();
Calendar calendar = Calendar.getInstance();
// building a cloud watch log client
AWSLogsClient cloudWatchlog = new AWSLogsClient(credential);
cloudWatchlog.setRegion(Region.getRegion(Regions.US_WEST_1));
// building a put request log
PutLogEventsRequest request = new PutLogEventsRequest();
request.setLogGroupName(LOG_GROUP);
request.setLogStreamName(LOG_STREAM);
// building my log event
InputLogEvent log = new InputLogEvent();
log.setMessage("Some message for a test");
log.setTimestamp(calendar.getTimeInMillis());
// building the array list log event
ArrayList<InputLogEvent> logEvents = new ArrayList<InputLogEvent>();
logEvents.add(log);
// setting the error array list
request.setLogEvents(logEvents);
// make the request
cloudWatchlog.putLogEvents(request);
System.out.println("done!");
}
}
当我运行第一次对码时一切正常,消息保存成功
但是,当我第二次执行代码时,出现以下异常:
Exception in thread "main" com.amazonaws.services.logs.model.InvalidSequenceTokenException: The given sequenceToken is invalid. The next expected sequenceToken is: xxxxxxxxxxxxxxxxxxxxxxxxxxx (Service: AWSLogs; Status Code: 400; Error Code: InvalidSequenceTokenException; Request ID: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)
at com.amazonaws.http.AmazonHttpClient.handleErrorResponse(AmazonHttpClient.java:1389)
XXXXXXXXXXX : 是亚马逊生成的令牌代码。
阅读亚马逊文档,我发现了以下信息:
请求语法:
{
"LogEvents": [
{
"Message": "string",
"Timestamp": number
}
],
"LogGroupName": "string",
"LogStreamName": "string",
"SequenceToken": "string"
}
SequenceToken
A string token that must be obtained from the response of the previous PutLogEvents request.
Type: String
Length constraints: Minimum length of 1.
Required: No
amazon documentation about cloud watch log REST API
我决定在我的代码中硬编码序列标记,如下所示:
request.setSequenceToken("58523.......");
它工作正常。我只是为了测试才做的。
最后,我发现获取序列标记的唯一方法是。
PutLogEventsResult response = cloudWatchlog.putLogEvents(request);
String token = response.getNextSequenceToken();
如何在发出请求之前验证并获取序列码?我在文档中找不到它。
您通常会在调用 putLogEvents (getNextSequenceToken) 时获得 nextToken。如果有不止一个生产者向流推送,他们在竞争并且一次只有一个可以推送(即:如果你得到一个令牌而其他人推送它会使你的令牌无效)。
如果发生这种情况,您需要描述流并获取新令牌:http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_DescribeLogStreams.html
所以模式是: 1) 如果您没有有效令牌或根本没有令牌(您才刚刚开始),请描述流以找出令牌。 2)使用您获得的令牌进行推送。如果推送成功更新令牌 3)若推送不成功,则转1),获取新的token,重试。如果有多个生产者,您可能需要尝试多次(即循环)。
我遇到了同样的问题并使用以下方法解决了它:
String token = logStream.getUploadSequenceToken();
完整源码:
public CloudWatchHandler(String logGroupName, String logStreamName) {
credentials = new DefaultAWSCredentialsProviderChain().getCredentials();
awsLogsClient = new AWSLogsClient(credentials);
awsLogsClient.setRegion(Region.getRegion(Regions.US_WEST_2));
this.logGroupName = logGroupName;
this.logStreamName = logStreamName;
logStreamsRequest = new DescribeLogStreamsRequest(logGroupName);
logStreamList = new ArrayList<LogStream>();
putLogEventsRequest = new PutLogEventsRequest();
putLogEventsResult = new PutLogEventsResult();
}
public void log(String message) {
logEvents = new ArrayList<InputLogEvent>();
log = new InputLogEvent();
calendar = Calendar.getInstance();
log.setTimestamp(calendar.getTimeInMillis());
log.setMessage(message);
logEvents.add(log);
logStreamsRequest.withLimit(5);
logStreamList= awsLogsClient.describeLogStreams(logStreamsRequest).getLogStreams();
for (LogStream logStream: logStreamList) {
if (logStream.getLogStreamName().equals(logStreamName))
token = logStream.getUploadSequenceToken();
}
if (token!=null) {
putLogEventsRequest.setLogGroupName(logGroupName);
putLogEventsRequest.setLogStreamName(logStreamName);
putLogEventsRequest.setLogEvents(logEvents);
putLogEventsRequest.setSequenceToken(token);
putLogEventsResult = awsLogsClient.putLogEvents(putLogEventsRequest);
}
}
我在使用当前发布的代码时仍然遇到了一些问题,所以我将添加我的工作解决方案来帮助解决问题:
"logStream.getLogStreamName()"
返回的不仅仅是流的名称,所以我通过使用 DescribeLogStreamsRequest().withLogGroupName("myCrAzYLogGroup");
//creds
String awsAccessKey = System.getProperty("AWS_ACCESS_KEY_ID");
String awsSecretKey = System.getProperty("AWS_SECRET_ACCESS_KEY");
Calendar calendar = Calendar.getInstance();
AWSCredentials credential = new BasicAWSCredentials(awsAccessKey, awsSecretKey);
AWSLogsClient awsLogsClient = new AWSLogsClient(credential);
awsLogsClient.setRegion(Region.getRegion(Regions.US_WEST_2));
//only difference in my code (i wanted to point out) is the use of BasicAWSCredentials
//AWSCredentials credential = CredentialBuilder.getCredential();
//AWSLogsClient cloudWatchlog = new AWSLogsClient(credential);
PutLogEventsRequest putLogEventsRequest = new PutLogEventsRequest();
putLogEventsRequest.setLogGroupName("myCrAzYLogGroup");
putLogEventsRequest.setLogStreamName("myCrAzYLogStream");
String token = null;
//here's mainly what I changed
DescribeLogStreamsRequest logStreamsRequest = new DescribeLogStreamsRequest().withLogGroupName("myCrAzYLogGroup");
List<LogStream> logStreamList = new ArrayList<LogStream>();
logStreamList= awsLogsClient.describeLogStreams(logStreamsRequest).getLogStreams();
//the answer to this question (get the token and use it)
//keep in mind I'm not comparing because I only have one stream
//again this is just to help get started/trouble shoot with a simplified setup
for (LogStream logStream: logStreamList) {
token = logStream.getUploadSequenceToken();
}
if(token != null)
{
putLogEventsRequest.setSequenceToken(token);
}
InputLogEvent testEvent = new InputLogEvent();
testEvent.setMessage("let's test this log!");
testEvent.setTimestamp(calendar.getTimeInMillis());
ArrayList<InputLogEvent> logEvents = new ArrayList<InputLogEvent>();
logEvents.add(testEvent);
putLogEventsRequest.setLogEvents(logEvents);
PutLogEventsResult putLogEventsResult = new PutLogEventsResult();
//this will return the next token if you want to hold onto it
putLogEventsResult = awsLogsClient.putLogEvents(putLogEventsRequest);