1# Copyright (c) 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved 2# 3# Permission is hereby granted, free of charge, to any person obtaining a 4# copy of this software and associated documentation files (the 5# "Software"), to deal in the Software without restriction, including 6# without limitation the rights to use, copy, modify, merge, publish, dis- 7# tribute, sublicense, and/or sell copies of the Software, and to permit 8# persons to whom the Software is furnished to do so, subject to the fol- 9# lowing conditions: 10# 11# The above copyright notice and this permission notice shall be included 12# in all copies or substantial portions of the Software. 13# 14# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- 16# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 17# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20# IN THE SOFTWARE. 21# 22 23import boto 24from boto.connection import AWSQueryConnection 25from boto.regioninfo import RegionInfo 26from boto.exception import JSONResponseError 27from boto.logs import exceptions 28from boto.compat import json 29 30 31class CloudWatchLogsConnection(AWSQueryConnection): 32 """ 33 Amazon CloudWatch Logs Service API Reference 34 This is the Amazon CloudWatch Logs API Reference . Amazon 35 CloudWatch Logs is a managed service for real time monitoring and 36 archival of application logs. This guide provides detailed 37 information about Amazon CloudWatch Logs actions, data types, 38 parameters, and errors. For detailed information about Amazon 39 CloudWatch Logs features and their associated API calls, go to the 40 `Amazon CloudWatch Logs Developer Guide`_. 41 42 Use the following links to get started using the Amazon CloudWatch 43 API Reference : 44 45 46 + `Actions`_: An alphabetical list of all Amazon CloudWatch Logs 47 actions. 48 + `Data Types`_: An alphabetical list of all Amazon CloudWatch 49 Logs data types. 50 + `Common Parameters`_: Parameters that all Query actions can use. 51 + `Common Errors`_: Client and server errors that all actions can 52 return. 53 + `Regions and Endpoints`_: Itemized regions and endpoints for all 54 AWS products. 55 56 57 In addition to using the Amazon CloudWatch Logs API, you can also 58 use the following SDKs and third-party libraries to access Amazon 59 CloudWatch Logs programmatically. 60 61 62 + `AWS SDK for Java Documentation`_ 63 + `AWS SDK for .NET Documentation`_ 64 + `AWS SDK for PHP Documentation`_ 65 + `AWS SDK for Ruby Documentation`_ 66 67 68 Developers in the AWS developer community also provide their own 69 libraries, which you can find at the following AWS developer 70 centers: 71 72 73 + `AWS Java Developer Center`_ 74 + `AWS PHP Developer Center`_ 75 + `AWS Python Developer Center`_ 76 + `AWS Ruby Developer Center`_ 77 + `AWS Windows and .NET Developer Center`_ 78 """ 79 APIVersion = "2014-03-28" 80 DefaultRegionName = "us-east-1" 81 DefaultRegionEndpoint = "logs.us-east-1.amazonaws.com" 82 ServiceName = "CloudWatchLogs" 83 TargetPrefix = "Logs_20140328" 84 ResponseError = JSONResponseError 85 86 _faults = { 87 "LimitExceededException": exceptions.LimitExceededException, 88 "DataAlreadyAcceptedException": exceptions.DataAlreadyAcceptedException, 89 "ResourceInUseException": exceptions.ResourceInUseException, 90 "ServiceUnavailableException": exceptions.ServiceUnavailableException, 91 "InvalidParameterException": exceptions.InvalidParameterException, 92 "ResourceNotFoundException": exceptions.ResourceNotFoundException, 93 "ResourceAlreadyExistsException": exceptions.ResourceAlreadyExistsException, 94 "OperationAbortedException": exceptions.OperationAbortedException, 95 "InvalidSequenceTokenException": exceptions.InvalidSequenceTokenException, 96 } 97 98 def __init__(self, **kwargs): 99 region = kwargs.pop('region', None) 100 if not region: 101 region = RegionInfo(self, self.DefaultRegionName, 102 self.DefaultRegionEndpoint) 103 104 if 'host' not in kwargs or kwargs['host'] is None: 105 kwargs['host'] = region.endpoint 106 107 super(CloudWatchLogsConnection, self).__init__(**kwargs) 108 self.region = region 109 110 def _required_auth_capability(self): 111 return ['hmac-v4'] 112 113 def create_log_group(self, log_group_name): 114 """ 115 Creates a new log group with the specified name. The name of 116 the log group must be unique within a region for an AWS 117 account. You can create up to 100 log groups per account. 118 119 You must use the following guidelines when naming a log group: 120 121 + Log group names can be between 1 and 512 characters long. 122 + Allowed characters are az, AZ, 09, '_' (underscore), '-' 123 (hyphen), '/' (forward slash), and '.' (period). 124 125 126 127 Log groups are created with a default retention of 14 days. 128 The retention attribute allow you to configure the number of 129 days you want to retain log events in the specified log group. 130 See the `SetRetention` operation on how to modify the 131 retention of your log groups. 132 133 :type log_group_name: string 134 :param log_group_name: 135 136 """ 137 params = {'logGroupName': log_group_name, } 138 return self.make_request(action='CreateLogGroup', 139 body=json.dumps(params)) 140 141 def create_log_stream(self, log_group_name, log_stream_name): 142 """ 143 Creates a new log stream in the specified log group. The name 144 of the log stream must be unique within the log group. There 145 is no limit on the number of log streams that can exist in a 146 log group. 147 148 You must use the following guidelines when naming a log 149 stream: 150 151 + Log stream names can be between 1 and 512 characters long. 152 + The ':' colon character is not allowed. 153 154 :type log_group_name: string 155 :param log_group_name: 156 157 :type log_stream_name: string 158 :param log_stream_name: 159 160 """ 161 params = { 162 'logGroupName': log_group_name, 163 'logStreamName': log_stream_name, 164 } 165 return self.make_request(action='CreateLogStream', 166 body=json.dumps(params)) 167 168 def delete_log_group(self, log_group_name): 169 """ 170 Deletes the log group with the specified name. Amazon 171 CloudWatch Logs will delete a log group only if there are no 172 log streams and no metric filters associated with the log 173 group. If this condition is not satisfied, the request will 174 fail and the log group will not be deleted. 175 176 :type log_group_name: string 177 :param log_group_name: 178 179 """ 180 params = {'logGroupName': log_group_name, } 181 return self.make_request(action='DeleteLogGroup', 182 body=json.dumps(params)) 183 184 def delete_log_stream(self, log_group_name, log_stream_name): 185 """ 186 Deletes a log stream and permanently deletes all the archived 187 log events associated with it. 188 189 :type log_group_name: string 190 :param log_group_name: 191 192 :type log_stream_name: string 193 :param log_stream_name: 194 195 """ 196 params = { 197 'logGroupName': log_group_name, 198 'logStreamName': log_stream_name, 199 } 200 return self.make_request(action='DeleteLogStream', 201 body=json.dumps(params)) 202 203 def delete_metric_filter(self, log_group_name, filter_name): 204 """ 205 Deletes a metric filter associated with the specified log 206 group. 207 208 :type log_group_name: string 209 :param log_group_name: 210 211 :type filter_name: string 212 :param filter_name: The name of the metric filter. 213 214 """ 215 params = { 216 'logGroupName': log_group_name, 217 'filterName': filter_name, 218 } 219 return self.make_request(action='DeleteMetricFilter', 220 body=json.dumps(params)) 221 222 def delete_retention_policy(self, log_group_name): 223 """ 224 225 226 :type log_group_name: string 227 :param log_group_name: 228 229 """ 230 params = {'logGroupName': log_group_name, } 231 return self.make_request(action='DeleteRetentionPolicy', 232 body=json.dumps(params)) 233 234 def describe_log_groups(self, log_group_name_prefix=None, 235 next_token=None, limit=None): 236 """ 237 Returns all the log groups that are associated with the AWS 238 account making the request. The list returned in the response 239 is ASCII-sorted by log group name. 240 241 By default, this operation returns up to 50 log groups. If 242 there are more log groups to list, the response would contain 243 a `nextToken` value in the response body. You can also limit 244 the number of log groups returned in the response by 245 specifying the `limit` parameter in the request. 246 247 :type log_group_name_prefix: string 248 :param log_group_name_prefix: 249 250 :type next_token: string 251 :param next_token: A string token used for pagination that points to 252 the next page of results. It must be a value obtained from the 253 response of the previous `DescribeLogGroups` request. 254 255 :type limit: integer 256 :param limit: The maximum number of items returned in the response. If 257 you don't specify a value, the request would return up to 50 items. 258 259 """ 260 params = {} 261 if log_group_name_prefix is not None: 262 params['logGroupNamePrefix'] = log_group_name_prefix 263 if next_token is not None: 264 params['nextToken'] = next_token 265 if limit is not None: 266 params['limit'] = limit 267 return self.make_request(action='DescribeLogGroups', 268 body=json.dumps(params)) 269 270 def describe_log_streams(self, log_group_name, 271 log_stream_name_prefix=None, next_token=None, 272 limit=None): 273 """ 274 Returns all the log streams that are associated with the 275 specified log group. The list returned in the response is 276 ASCII-sorted by log stream name. 277 278 By default, this operation returns up to 50 log streams. If 279 there are more log streams to list, the response would contain 280 a `nextToken` value in the response body. You can also limit 281 the number of log streams returned in the response by 282 specifying the `limit` parameter in the request. 283 284 :type log_group_name: string 285 :param log_group_name: 286 287 :type log_stream_name_prefix: string 288 :param log_stream_name_prefix: 289 290 :type next_token: string 291 :param next_token: A string token used for pagination that points to 292 the next page of results. It must be a value obtained from the 293 response of the previous `DescribeLogStreams` request. 294 295 :type limit: integer 296 :param limit: The maximum number of items returned in the response. If 297 you don't specify a value, the request would return up to 50 items. 298 299 """ 300 params = {'logGroupName': log_group_name, } 301 if log_stream_name_prefix is not None: 302 params['logStreamNamePrefix'] = log_stream_name_prefix 303 if next_token is not None: 304 params['nextToken'] = next_token 305 if limit is not None: 306 params['limit'] = limit 307 return self.make_request(action='DescribeLogStreams', 308 body=json.dumps(params)) 309 310 def describe_metric_filters(self, log_group_name, 311 filter_name_prefix=None, next_token=None, 312 limit=None): 313 """ 314 Returns all the metrics filters associated with the specified 315 log group. The list returned in the response is ASCII-sorted 316 by filter name. 317 318 By default, this operation returns up to 50 metric filters. If 319 there are more metric filters to list, the response would 320 contain a `nextToken` value in the response body. You can also 321 limit the number of metric filters returned in the response by 322 specifying the `limit` parameter in the request. 323 324 :type log_group_name: string 325 :param log_group_name: 326 327 :type filter_name_prefix: string 328 :param filter_name_prefix: The name of the metric filter. 329 330 :type next_token: string 331 :param next_token: A string token used for pagination that points to 332 the next page of results. It must be a value obtained from the 333 response of the previous `DescribeMetricFilters` request. 334 335 :type limit: integer 336 :param limit: The maximum number of items returned in the response. If 337 you don't specify a value, the request would return up to 50 items. 338 339 """ 340 params = {'logGroupName': log_group_name, } 341 if filter_name_prefix is not None: 342 params['filterNamePrefix'] = filter_name_prefix 343 if next_token is not None: 344 params['nextToken'] = next_token 345 if limit is not None: 346 params['limit'] = limit 347 return self.make_request(action='DescribeMetricFilters', 348 body=json.dumps(params)) 349 350 def get_log_events(self, log_group_name, log_stream_name, 351 start_time=None, end_time=None, next_token=None, 352 limit=None, start_from_head=None): 353 """ 354 Retrieves log events from the specified log stream. You can 355 provide an optional time range to filter the results on the 356 event `timestamp`. 357 358 By default, this operation returns as much log events as can 359 fit in a response size of 1MB, up to 10,000 log events. The 360 response will always include a `nextForwardToken` and a 361 `nextBackwardToken` in the response body. You can use any of 362 these tokens in subsequent `GetLogEvents` requests to paginate 363 through events in either forward or backward direction. You 364 can also limit the number of log events returned in the 365 response by specifying the `limit` parameter in the request. 366 367 :type log_group_name: string 368 :param log_group_name: 369 370 :type log_stream_name: string 371 :param log_stream_name: 372 373 :type start_time: long 374 :param start_time: A point in time expressed as the number milliseconds 375 since Jan 1, 1970 00:00:00 UTC. 376 377 :type end_time: long 378 :param end_time: A point in time expressed as the number milliseconds 379 since Jan 1, 1970 00:00:00 UTC. 380 381 :type next_token: string 382 :param next_token: A string token used for pagination that points to 383 the next page of results. It must be a value obtained from the 384 `nextForwardToken` or `nextBackwardToken` fields in the response of 385 the previous `GetLogEvents` request. 386 387 :type limit: integer 388 :param limit: The maximum number of log events returned in the 389 response. If you don't specify a value, the request would return as 390 much log events as can fit in a response size of 1MB, up to 10,000 391 log events. 392 393 :type start_from_head: boolean 394 :param start_from_head: 395 396 """ 397 params = { 398 'logGroupName': log_group_name, 399 'logStreamName': log_stream_name, 400 } 401 if start_time is not None: 402 params['startTime'] = start_time 403 if end_time is not None: 404 params['endTime'] = end_time 405 if next_token is not None: 406 params['nextToken'] = next_token 407 if limit is not None: 408 params['limit'] = limit 409 if start_from_head is not None: 410 params['startFromHead'] = start_from_head 411 return self.make_request(action='GetLogEvents', 412 body=json.dumps(params)) 413 414 def put_log_events(self, log_group_name, log_stream_name, log_events, 415 sequence_token=None): 416 """ 417 Uploads a batch of log events to the specified log stream. 418 419 Every PutLogEvents request must include the `sequenceToken` 420 obtained from the response of the previous request. An upload 421 in a newly created log stream does not require a 422 `sequenceToken`. 423 424 The batch of events must satisfy the following constraints: 425 426 + The maximum batch size is 32,768 bytes, and this size is 427 calculated as the sum of all event messages in UTF-8, plus 26 428 bytes for each log event. 429 + None of the log events in the batch can be more than 2 hours 430 in the future. 431 + None of the log events in the batch can be older than 14 432 days or the retention period of the log group. 433 + The log events in the batch must be in chronological ordered 434 by their `timestamp`. 435 + The maximum number of log events in a batch is 1,000. 436 437 :type log_group_name: string 438 :param log_group_name: 439 440 :type log_stream_name: string 441 :param log_stream_name: 442 443 :type log_events: list 444 :param log_events: A list of events belonging to a log stream. 445 446 :type sequence_token: string 447 :param sequence_token: A string token that must be obtained from the 448 response of the previous `PutLogEvents` request. 449 450 """ 451 params = { 452 'logGroupName': log_group_name, 453 'logStreamName': log_stream_name, 454 'logEvents': log_events, 455 } 456 if sequence_token is not None: 457 params['sequenceToken'] = sequence_token 458 return self.make_request(action='PutLogEvents', 459 body=json.dumps(params)) 460 461 def put_metric_filter(self, log_group_name, filter_name, filter_pattern, 462 metric_transformations): 463 """ 464 Creates or updates a metric filter and associates it with the 465 specified log group. Metric filters allow you to configure 466 rules to extract metric data from log events ingested through 467 `PutLogEvents` requests. 468 469 :type log_group_name: string 470 :param log_group_name: 471 472 :type filter_name: string 473 :param filter_name: The name of the metric filter. 474 475 :type filter_pattern: string 476 :param filter_pattern: 477 478 :type metric_transformations: list 479 :param metric_transformations: 480 481 """ 482 params = { 483 'logGroupName': log_group_name, 484 'filterName': filter_name, 485 'filterPattern': filter_pattern, 486 'metricTransformations': metric_transformations, 487 } 488 return self.make_request(action='PutMetricFilter', 489 body=json.dumps(params)) 490 491 def put_retention_policy(self, log_group_name, retention_in_days): 492 """ 493 494 495 :type log_group_name: string 496 :param log_group_name: 497 498 :type retention_in_days: integer 499 :param retention_in_days: Specifies the number of days you want to 500 retain log events in the specified log group. Possible values are: 501 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 547, 730. 502 503 """ 504 params = { 505 'logGroupName': log_group_name, 506 'retentionInDays': retention_in_days, 507 } 508 return self.make_request(action='PutRetentionPolicy', 509 body=json.dumps(params)) 510 511 def set_retention(self, log_group_name, retention_in_days): 512 """ 513 Sets the retention of the specified log group. Log groups are 514 created with a default retention of 14 days. The retention 515 attribute allow you to configure the number of days you want 516 to retain log events in the specified log group. 517 518 :type log_group_name: string 519 :param log_group_name: 520 521 :type retention_in_days: integer 522 :param retention_in_days: Specifies the number of days you want to 523 retain log events in the specified log group. Possible values are: 524 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 547, 730. 525 526 """ 527 params = { 528 'logGroupName': log_group_name, 529 'retentionInDays': retention_in_days, 530 } 531 return self.make_request(action='SetRetention', 532 body=json.dumps(params)) 533 534 def test_metric_filter(self, filter_pattern, log_event_messages): 535 """ 536 Tests the filter pattern of a metric filter against a sample 537 of log event messages. You can use this operation to validate 538 the correctness of a metric filter pattern. 539 540 :type filter_pattern: string 541 :param filter_pattern: 542 543 :type log_event_messages: list 544 :param log_event_messages: 545 546 """ 547 params = { 548 'filterPattern': filter_pattern, 549 'logEventMessages': log_event_messages, 550 } 551 return self.make_request(action='TestMetricFilter', 552 body=json.dumps(params)) 553 554 def make_request(self, action, body): 555 headers = { 556 'X-Amz-Target': '%s.%s' % (self.TargetPrefix, action), 557 'Host': self.region.endpoint, 558 'Content-Type': 'application/x-amz-json-1.1', 559 'Content-Length': str(len(body)), 560 } 561 http_request = self.build_base_http_request( 562 method='POST', path='/', auth_path='/', params={}, 563 headers=headers, data=body) 564 response = self._mexe(http_request, sender=None, 565 override_num_retries=10) 566 response_body = response.read().decode('utf-8') 567 boto.log.debug(response_body) 568 if response.status == 200: 569 if response_body: 570 return json.loads(response_body) 571 else: 572 json_body = json.loads(response_body) 573 fault_name = json_body.get('__type', None) 574 exception_class = self._faults.get(fault_name, self.ResponseError) 575 raise exception_class(response.status, response.reason, 576 body=json_body) 577