2016-04-26 75 views
3

我正在为使用Amazon Cloud Watch服务的应用程序构建一个小型日志跟踪器。这个想法不是跟踪文件的日志输出,而是使用aws控制台的搜索引擎来查找日志信息。Amazon Cloud Watch日志 - PutLogEventsRequest - 给定的sequenceToken无效

我使用:

  • Eclipse作为IDE
  • 的Java 8个
  • 依赖关系:AWS-Java的SDK核心/ AWS-Java的SDK-CloudWatch的V 49年1月10日

在另一方面我有以下AWS配置:

  • 甲CCESS和私钥
  • 地区:加州
  • 日志组:demo1的
  • 日志流:流1

我在写下面的代码做一个简单的功能测试:

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!"); 
    } 
} 

当我第一次运行代码时,所有的都是okey,消息被成功保存。

enter image description here

然而,当我执行的代码,第二次我得到以下异常:

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(); 

我如何可以验证并获得序列码提出请求之前?我无法在文档中找到它。

回答

2

当您对putLogEvents(getNextSequenceToken)进行调用时,通常会得到nextToken。如果有多个生产者推送到流中,他们就会竞争,并且他们中只有一个可以一次推送(即:如果您获得一个令牌并且其他人推送它,则令牌无效)。

如果发生这种情况,你需要描述流,并得到一个新的令牌:http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_DescribeLogStreams.html

所以该模式是: 1)如果你没有一个有效的标记或没有标记在所有(你刚刚开始)描述流来找出令牌。 2)使用您拥有的令牌推送。如果推送成功,更新令牌 3)如果推送不成功,请转到1),获取新令牌并重试。如果有多个生产者,您可能需要尝试多次(即循环)。

2

我有同样的问题,用解决它:

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); 
    }  
} 
+0

这也是一个好方法 – afym

0

我有一些麻烦仍与目前的代码发布,所以我会加入我的工作解决方案以帮助排除故障:

"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); 
相关问题