AWS-CloudWatch: InvalidSequenceTokenException
This is my working solution: before send new putLogEvents you must take the last uploadSequenceToken.
try {
$client = \Aws\CloudWatchLogs\CloudWatchLogsClient::factory($configCloudWatch);
$logStreamName = 'testLogStream';
$logGroupName = 'testGroupName';
$result = $client->describeLogStreams([
'logGroupName' => $logGroupName,
'logStreamNamePrefix' => $logStreamName,
]);
$logStreams=$result->get('logStreams');
if (!$logStreams)
throw new \Exception('No log stream found');
if (count($logStreams)!=1)
throw new \Exception('Multiple log stream found');
$uploadSequenceToken = $logStreams[0]['uploadSequenceToken'];
$client->putLogEvents([
'logGroupName' => $logGroupName,
'logStreamName' => $logStreamName,
'logEvents' => [
[
'timestamp' => round(microtime(true) * 1000),
// message is required
'message' => json_encode([ ... ]
),
],
],
'sequenceToken' => $uploadSequenceToken,
]);
} catch (\Exception $e) {
\Log::error(__METHOD__, ['exception' => $e]);
}
The DescribeLogStreams
does not support the same volume call as PutLogEvent
. You may got throttled if calling it frequently.
The recommended way to do it is calling the PutLogEvents
directly and catch the InvalidSequenceTokenException
. Then retry the PutLogEvents
with Sequence Token in the InvalidSequenceTokenException
message.
Correct sequence token can be found in the expectedSequenceToken field of InvalidSequenceTokenException
try {
$result = $client->describeLogStreams([
'logGroupName' => $logGroupName,
'logStreamNamePrefix' => $logStreamName,
]);
$uploadSequenceToken = $logStreams[0]['uploadSequenceToken'];
$client->putLogEvents([
'logGroupName' => $logGroupName,
'logStreamName' => $logStreamName,
'logEvents' => [
[
'timestamp' => $timestamp,
'message' => $message
],
],
'sequenceToken' => $uploadSequenceToken,
]);
} catch (\InvalidSequenceTokenException $e) {
$client->putLogEvents([
'logGroupName' => $logGroupName,
'logStreamName' => $logStreamName,
'logEvents' => [
[
'timestamp' => $timestamp,
'message' => $message
],
],
'sequenceToken' => $e->expectedSequenceToken,
]);
}
http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_PutLogEvents.html
You must include a sequence token with your request. If you don't have one you must use describeLogStreams (http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_DescribeLogStreams.html) to get the stream sequence.
When you make a call to putLogEvents you will get the nextToken in the response. You also must be ready for the case in which someone else pushes to the stream and invalidates the nextToken. (in this case you need to describe the stream again to get an updated token).