Python / Boto-无需序列令牌即可写入AWS CloudWatch Logs

Ole*_*lin 7 python boto amazon-web-services

我正在尝试使用Python和Boto框架将日志发送到AWS CloudWatch Logs。我正在这样做:

res=logs.put_log_events("FOO", "BAR",
     [{'timestamp':int(round(time.time() * 1000)),
       'message':time.strftime("%m/%d/%Y %H:%M:%S")+' Scheduled  monitoring check' }], 
     sequence_token=None)
Run Code Online (Sandbox Code Playgroud)

我每次运行都会收到错误消息:

boto.logs.exceptions.InvalidSequenceTokenException: InvalidSequenceTokenException: 400 Bad Request
{u'message': u'The given sequenceToken is invalid. The next expected sequenceToken is: 49540113336360065754596906019042392283494234157161146226', u'expectedSequenceToken': u'49540113336360065754596906019042392283494234157161146226', u'__type': u'InvalidSequenceTokenException'}
Run Code Online (Sandbox Code Playgroud)

对我来说,存储该令牌有点不切实际。这没有任何意义,为什么我不能仅附加到日志流?

我该如何解决?

小智 10

AWS Cloud Watch Putlogevent 代码

import boto3
import time


client = boto3.client('logs')

LOG_GROUP='cloudwatch_customlog'
LOG_STREAM='{}-{}'.format(time.strftime('%Y-%m-%d'),'logstream')

try:
   client.create_log_group(logGroupName=LOG_GROUP)
except client.exceptions.ResourceAlreadyExistsException:
   pass

try:
   client.create_log_stream(logGroupName=LOG_GROUP, logStreamName=LOG_STREAM)
except client.exceptions.ResourceAlreadyExistsException:
   pass

response = client.describe_log_streams(
   logGroupName=LOG_GROUP,
   logStreamNamePrefix=LOG_STREAM
)

event_log = {
   'logGroupName': LOG_GROUP,
   'logStreamName': LOG_STREAM,
   'logEvents': [
       {
           'timestamp': int(round(time.time() * 1000)),
           'message': time.strftime('%Y-%m-%d %H:%M:%S')+'\t Your custom log messages'
       }
   ],
}

if 'uploadSequenceToken' in response['logStreams'][0]:
   event_log.update({'sequenceToken': response['logStreams'][0] ['uploadSequenceToken']})

response = client.put_log_events(**event_log)
print(response)
Run Code Online (Sandbox Code Playgroud)


fau*_*onk 6

您可以通过首先通过describe_log_streams()查找uploadSequenceToken来解决它:

本质上,该过程是您使用logStreamNamePrefix专门标识要追加到的日志流。然后从响应中解析uploadSequenceToken。

响应语法

 {
     'logStreams': [
         {
             'logStreamName': 'string',
             'creationTime': 123,
             'firstEventTimestamp': 123,
             'lastEventTimestamp': 123,
             'lastIngestionTime': 123,
             'uploadSequenceToken': 'string',
             'arn': 'string',
             'storedBytes': 123
         },
     ],
     'nextToken': 'string'
 }
Run Code Online (Sandbox Code Playgroud)

返回与指定日志组关联的所有日志流。响应中返回的列表按日志流名称按ASCII排序。

默认情况下,此操作最多返回50个日志流。如果有更多日志流要列出,则响应将在响应正文中包含nextToken值。您还可以通过在请求中指定limit参数来限制响应中返回的日志流的数量。此操作的每秒限制为五个事务,之后限制事务。

请求语法

response = client.describe_log_streams(
    logGroupName='string',
    logStreamNamePrefix='string',
    orderBy='LogStreamName'|'LastEventTime',
    descending=True|False,
    nextToken='string',
    limit=123
)
Run Code Online (Sandbox Code Playgroud)

  • 不要使用DescribeLogStreams,因为它的每个区域每个帐户 5 TPS 的限制非常低,您很快就会开始受到限制。而是使用 PutLogEvents,它的 TPS 更高,每个日志流为 5 TPS。在 try except 块中执行没有序列标记的第一个 PutLogEvents,因为它将返回一个错误,并在响应错误中包含预期的序列标记。然后,在 except 块中再次执行 PutLogEvents API 调用时,只需使用返回的“预期序列令牌”即可。例如,如何执行此操作,请参阅https://gist.github.com/vatshat/63cad6f15082ec06851bb40eb0394931 (3认同)

Pie*_*nes 5

用有根据的猜测来回答为什么:这是可伸缩异步服务的本质。

如果Amazon 要求您维护序列号,那么他们将永远无法在多个实例上扩展CloudWatch服务,同时仍然能够确保您的日志以与发生的完全相同的顺序出现(并想像一下,有序日志条目将在调试问题时显示)。时钟,网络延迟或日志接受器路径上的其他任何细微偏差都会带来订购问题。

但是,由于他们确实要求您提供序列号,因此突然之间,他们可以轻松地扩展其服务,并且只需返回的日志条目合并排序即可,同时仍然保留正确的日志顺序(您的日志顺序)。