Packages
erlcloud
3.3.8
3.8.3
3.8.2
3.8.1
3.7.6
3.7.4
3.7.3
3.7.2
3.7.1
3.7.0
3.6.8
3.6.7
3.6.5
3.6.4
3.6.3
3.6.2
3.6.1
3.6.0
3.5.16
3.5.15
3.5.14
3.5.13
3.5.12
3.5.11
3.5.10
3.5.9
3.5.8
3.5.7
3.5.6
3.5.5
3.5.4
3.5.3
3.5.2
3.5.1
3.5.0
3.4.5
3.4.3
3.4.1
3.4.0
3.3.9
3.3.8
3.3.7
3.3.6
3.3.5
3.3.4
3.3.3
3.3.2
3.3.1
3.3.0
3.2.18
3.2.17
3.2.16
3.2.15
3.2.14
3.2.13
3.2.12
3.2.11
3.2.10
3.2.7
3.2.6
3.2.5
3.2.4
3.2.3
3.2.2
3.2.1
3.2.0
3.1.17
3.1.16
3.1.14
3.1.13
3.1.12
3.1.11
3.1.9
3.1.8
3.1.7
3.1.6
3.1.5
3.1.4
3.1.3
3.1.2
3.1.1
3.1.0
3.0.5
3.0.4
3.0.3
3.0.2
3.0.1
2.2.16
2.2.15
2.2.14
2.2.13
2.2.12
2.2.11
2.2.10
2.2.9
2.2.8
2.2.7
2.2.6
2.2.5
2.2.4
2.2.2
2.2.1
2.2.0
2.1.0
2.0.5
2.0.4
2.0.3
2.0.0
0.13.10
0.13.9
0.13.8
0.13.6
0.13.5
0.13.4
0.13.3
0.13.2
0.13.0
0.12.0
0.11.0
0.9.2
0.9.2-rc.1
0.9.1
0.9.0
AWS APIs library for Erlang
Current section
Files
Jump to
Current section
Files
src/erlcloud_cloudwatch_logs.erl
-module(erlcloud_cloudwatch_logs).
-include("erlcloud_aws.hrl").
-define(API_VERSION, "2014-03-28").
-define(API_PREFIX, "Logs_20140328").
-define(SERVICE_NAME, "logs").
-define(DEFAULT_LIMIT, 50).
-define(DEFAULT_HEADERS, [
{"content-type", "application/x-amz-json-1.1"},
{"accept", "application/json"}
]).
-type access_key_id() :: string().
-type secret_access_key() :: string().
-type cw_host() :: string().
-type paging_token() :: string() | binary() | undefined.
-type seq_token() :: string() | binary() | undefined.
-type log_group_name() :: string() | binary() | undefined.
-type log_group_name_prefix() :: string() | binary() | undefined.
-type log_stream_name() :: string() | binary() | undefined.
-type log_stream_prefix() :: string() | binary() | undefined.
-type limit() :: pos_integer() | undefined.
-type filter_name_prefix() :: string() | binary() | undefined.
-type metric_name() :: string() | binary() | undefined.
-type metric_namespace() :: string() | binary() | undefined.
-type log_stream_order() :: log_stream_name | last_event_time | undefined.
-type events() :: [#{message => binary(), timestamp => pos_integer()}].
-type kms_key_id() :: string() | binary() | undefined.
-type success_result_paged(ObjectType) :: {ok, [ObjectType], paging_token()}.
-type error_result() :: {error, Reason :: term()}.
-type result_paged(ObjectType) :: success_result_paged(ObjectType) | error_result().
-type log_group() :: jsx:json_term().
-type log_stream() :: jsx:json_term().
-type metric_filters() :: jsx:json_term().
-type tag():: {binary(), binary()}.
-type tags_return() :: {error, metadata_not_available
| container_credentials_unavailable
| erlcloud_aws:httpc_result_error()}
| {ok, jsx:json_term()}.
%% Library initialization
-export([
configure/2,
configure/3,
new/2,
new/3
]).
%% CloudWatch API
-export([
create_log_group/1,
create_log_group/2,
create_log_group/3,
create_log_group/4,
create_log_stream/2,
create_log_stream/3,
delete_log_group/1,
delete_log_group/2,
delete_log_stream/2,
delete_log_stream/3,
describe_log_groups/0,
describe_log_groups/1,
describe_log_groups/2,
describe_log_groups/3,
describe_log_groups/4,
describe_log_streams/1,
describe_log_streams/2,
describe_log_streams/3,
describe_log_streams/5,
describe_log_streams/6,
describe_log_streams/7,
describe_metric_filters/0,
describe_metric_filters/1,
describe_metric_filters/2,
describe_metric_filters/3,
describe_metric_filters/4,
describe_metric_filters/6,
describe_metric_filters/7,
put_logs_events/4,
put_logs_events/5,
list_tags_log_group/1,
list_tags_log_group/2,
tag_log_group/2,
tag_log_group/3
]).
%%==============================================================================
%% Library initialization
%%==============================================================================
-spec configure(access_key_id(), secret_access_key()) -> ok.
configure(AccessKeyID, SecretAccessKey) ->
put(aws_config, new(AccessKeyID, SecretAccessKey)),
ok.
-spec configure(access_key_id(), secret_access_key(), cw_host()) -> ok.
configure(AccessKeyID, SecretAccessKey, Host) ->
put(aws_config, new(AccessKeyID, SecretAccessKey, Host)),
ok.
-spec new(access_key_id(), secret_access_key()) -> aws_config().
new(AccessKeyID, SecretAccessKey) ->
#aws_config{
access_key_id = AccessKeyID,
secret_access_key = SecretAccessKey
}.
-spec new(access_key_id(), secret_access_key(), cw_host()) -> aws_config().
new(AccessKeyID, SecretAccessKey, Host) ->
#aws_config{
access_key_id = AccessKeyID,
secret_access_key = SecretAccessKey,
cloudwatch_logs_host = Host
}.
%%==============================================================================
%% CloudWatch API
%%==============================================================================
%%------------------------------------------------------------------------------
%% @doc
%%
%% CreateLogGroup action
%% http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogGroup.html
%%
%% @end
%%------------------------------------------------------------------------------
-spec create_log_group(log_group_name()) -> ok | error_result().
create_log_group(LogGroupName) ->
create_log_group(LogGroupName, default_config()).
-spec create_log_group(
log_group_name(),
aws_config()
) -> ok | error_result().
create_log_group(LogGroupName, Config) ->
create_log_group(LogGroupName, undefined, undefined, Config).
-spec create_log_group(
log_group_name(),
list(tag()),
aws_config()
) -> ok | error_result().
create_log_group(LogGroupName, Tags, Config) when is_list(Tags) ->
create_log_group(LogGroupName, Tags, undefined, Config).
-spec create_log_group(
log_group_name(),
undefined | list(tag()),
undefined | kms_key_id(),
aws_config()
) -> ok | error_result().
create_log_group(LogGroupName, Tags, KmsKeyId, Config) ->
case cw_request(Config, "CreateLogGroup", [
{<<"logGroupName">>, LogGroupName},
{<<"tags">>, Tags},
{<<"kmsKeyId">>, KmsKeyId}
])
of
{ok, []} -> ok;
{error, _} = Error -> Error
end.
%%------------------------------------------------------------------------------
%% @doc
%%
%% CreateLogStream action
%% http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogStream.html
%%
%% @end
%%------------------------------------------------------------------------------
-spec create_log_stream(
log_group_name(),
log_stream_name()
) -> ok | error_result().
create_log_stream(LogGroupName, LogStreamName) ->
create_log_stream(LogGroupName, LogStreamName, default_config()).
-spec create_log_stream(
log_group_name(),
log_stream_name(),
aws_config()
) -> ok | error_result().
create_log_stream(LogGroupName, LogStreamName, Config) ->
case cw_request(Config, "CreateLogStream", [
{<<"logGroupName">>, LogGroupName},
{<<"logStreamName">>, LogStreamName}
])
of
{ok, []} -> ok;
{error, _} = Error -> Error
end.
%%------------------------------------------------------------------------------
%% @doc
%%
%% DeleteLogGroup action
%% http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_DeleteLogGroup.html
%%
%% @end
%%------------------------------------------------------------------------------
-spec delete_log_group(log_group_name()) -> ok | error_result().
delete_log_group(LogGroupName) ->
delete_log_group(LogGroupName, default_config()).
-spec delete_log_group(
log_group_name(),
aws_config()
) -> ok | error_result().
delete_log_group(LogGroupName, Config) ->
case cw_request(Config, "DeleteLogGroup", [
{<<"logGroupName">>, LogGroupName}
])
of
{ok, []} -> ok;
{error, _} = Error -> Error
end.
%%------------------------------------------------------------------------------
%% @doc
%%
%% DeleteLogStream action
%% http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_DeleteLogStream.html
%%
%% @end
%%------------------------------------------------------------------------------
-spec delete_log_stream(
log_group_name(),
log_stream_name()
) -> ok | error_result().
delete_log_stream(LogGroupName, LogStreamName) ->
delete_log_stream(LogGroupName, LogStreamName, default_config()).
-spec delete_log_stream(
log_group_name(),
log_stream_name(),
aws_config()
) -> ok | error_result().
delete_log_stream(LogGroupName, LogStreamName, Config) ->
case cw_request(Config, "DeleteLogStream", [
{<<"logGroupName">>, LogGroupName},
{<<"logStreamName">>, LogStreamName}
])
of
{ok, []} -> ok;
{error, _} = Error -> Error
end.
%%------------------------------------------------------------------------------
%% @doc
%%
%% DescribeLogGroups action
%% http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_DescribeLogGroups.html
%%
%% @end
%%------------------------------------------------------------------------------
-spec describe_log_groups() -> result_paged(log_group()).
describe_log_groups() ->
describe_log_groups(default_config()).
-spec describe_log_groups(
aws_config() | log_group_name_prefix()
) -> result_paged(log_group()).
describe_log_groups(#aws_config{} = Config) ->
describe_log_groups(undefined, Config);
describe_log_groups(LogGroupNamePrefix) ->
describe_log_groups(LogGroupNamePrefix, default_config()).
-spec describe_log_groups(
log_group_name_prefix(),
aws_config()
) -> result_paged(log_group()).
describe_log_groups(LogGroupNamePrefix, Config) ->
describe_log_groups(LogGroupNamePrefix, ?DEFAULT_LIMIT, Config).
-spec describe_log_groups(
log_group_name_prefix(),
limit(),
aws_config()
) -> result_paged(log_group()).
describe_log_groups(LogGroupNamePrefix, Limit, Config) ->
describe_log_groups(LogGroupNamePrefix, Limit, undefined, Config).
-spec describe_log_groups(
log_group_name_prefix(),
limit(),
paging_token(),
aws_config()
) -> result_paged(log_group()).
describe_log_groups(LogGroupNamePrefix, Limit, Token, Config) ->
case
cw_request(Config, "DescribeLogGroups",
req_log_groups(LogGroupNamePrefix, Limit, Token)
)
of
{ok, Json} ->
LogGroups = proplists:get_value(<<"logGroups">>, Json, []),
NextToken = proplists:get_value(<<"nextToken">>, Json, undefined),
{ok, LogGroups, NextToken};
{error, _} = Error ->
Error
end.
req_log_groups(LogGroupNamePrefix, Limit, Token) ->
[
{<<"limit">>, Limit},
{<<"logGroupNamePrefix">>, LogGroupNamePrefix},
{<<"nextToken">>, Token}
].
%%------------------------------------------------------------------------------
%% @doc
%%
%% DescribeLogStreams action
%% https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_DescribeLogStreams.html
%%
%% @end
%%------------------------------------------------------------------------------
-spec describe_log_streams(log_group_name()) -> result_paged(log_stream()).
describe_log_streams(LogGroupName) ->
describe_log_streams(LogGroupName, default_config()).
-spec describe_log_streams(
log_group_name(),
aws_config()
) -> result_paged(log_stream()).
describe_log_streams(LogGroupName, Config) ->
describe_log_streams(LogGroupName, undefined, Config).
-spec describe_log_streams(
log_group_name(),
log_stream_prefix(),
aws_config()
) -> result_paged(log_stream()).
describe_log_streams(LogGroupName, LogStreamPrefix, Config) ->
describe_log_streams(LogGroupName, LogStreamPrefix, log_stream_name, false, Config).
-spec describe_log_streams(
log_group_name(),
log_stream_prefix(),
log_stream_order(),
boolean(),
aws_config()
) -> result_paged(log_stream()).
describe_log_streams(LogGroupName, LogStreamPrefix, OrderBy, Desc, Config) ->
describe_log_streams(LogGroupName, LogStreamPrefix, OrderBy, Desc, ?DEFAULT_LIMIT, Config).
-spec describe_log_streams(
log_group_name(),
log_stream_prefix(),
log_stream_order(),
boolean(),
limit(),
aws_config()
) -> result_paged(log_stream()).
describe_log_streams(LogGroupName, LogStreamPrefix, OrderBy, Desc, Limit, Config) ->
describe_log_streams(LogGroupName, LogStreamPrefix, OrderBy, Desc, Limit, undefined, Config).
-spec describe_log_streams(
log_group_name(),
log_stream_prefix(),
log_stream_order(),
boolean(),
limit(),
paging_token(),
aws_config()
) -> result_paged(log_stream()).
describe_log_streams(LogGroupName, LogStreamPrefix, OrderBy, Desc, Limit, Token, Config) ->
case
cw_request(Config, "DescribeLogStreams",
req_log_streams(LogGroupName, LogStreamPrefix, OrderBy, Desc, Limit, Token)
)
of
{ok, Json} ->
LogStream = proplists:get_value(<<"logStreams">>, Json, []),
NextToken = proplists:get_value(<<"nextToken">>, Json, undefined),
{ok, LogStream, NextToken};
{error, _} = Error ->
Error
end.
req_log_streams(LogGroupName, LogStreamPrefix, OrderBy, Desc, Limit, Token) ->
[
{<<"descending">>, Desc},
{<<"limit">>, Limit},
{<<"logGroupName">>, LogGroupName},
{<<"logStreamNamePrefix">>, LogStreamPrefix},
{<<"nextToken">>, Token},
{<<"orderBy">>, log_stream_order_by(OrderBy)}
].
log_stream_order_by(undefined) -> <<"LogStreamName">>;
log_stream_order_by(log_stream_name) -> <<"LogStreamName">>;
log_stream_order_by(last_event_time) -> <<"LastEventTime">>.
%%------------------------------------------------------------------------------
%% @doc
%%
%% PutLogEvents action
%% https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_PutLogEvents.html
%%
%% ===Example===
%%
%% Put log events requires a Upload Sequence Token, it is available via DescribeLogStreams
%%
%% `
%% application:ensure_all_started(erlcloud).
%% {ok, Config} = erlcloud_aws:auto_config().
%% {ok, Streams, _} = erlcloud_cloudwatch_logs:describe_log_streams(GroupName, StreamName, Config).
%% {_, Seq} = lists:keyfind(<<"uploadSequenceToken">>, 1, hd(Streams)).
%%
%% Batch = [#{timestamp => 1526233086694, message => <<"Example Message">>}].
%% erlcloud_cloudwatch_logs:put_logs_events(GroupName, StreamName, Seq, Batch, Config).
%% `
%%
%% @end
%%------------------------------------------------------------------------------
-spec put_logs_events(
log_group_name(),
log_stream_name(),
seq_token(),
events()
) -> {ok, seq_token()} | {error, erlcloud_aws:httpc_result_error()}.
put_logs_events(LogGroup, LogStream, SeqToken, Events) ->
put_logs_events(LogGroup, LogStream, SeqToken, Events, default_config()).
-spec put_logs_events(
log_group_name(),
log_stream_name(),
seq_token(),
events(),
aws_config()
) -> {ok, seq_token()} | {error, erlcloud_aws:httpc_result_error()}.
put_logs_events(LogGroup, LogStream, SeqToken, Events, Config) ->
case
cw_request(Config, "PutLogEvents",
req_logs_events(LogGroup, LogStream, SeqToken, Events)
)
of
{ok, Json} ->
Seq = proplists:get_value(<<"nextSequenceToken">>, Json, []),
{ok, Seq};
{error, _} = Error ->
Error
end.
req_logs_events(LogGroup, LogStream, SeqToken, Events) ->
[
{<<"logEvents">>, log_events(Events)},
{<<"logGroupName">>, LogGroup},
{<<"logStreamName">>, LogStream},
{<<"sequenceToken">>, SeqToken}
].
log_events(Events) ->
[maps:with([message, timestamp], X) ||
#{message := _, timestamp := _} = X <- Events].
%%------------------------------------------------------------------------------
%% @doc
%%
%% DescribeMetricFilters action
%% https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_DescribeMetricFilters.html
%%
%% @end
%%------------------------------------------------------------------------------
-spec describe_metric_filters() -> result_paged(metric_filters()).
describe_metric_filters() ->
describe_metric_filters(default_config()).
-spec describe_metric_filters(
aws_config() | log_group_name()
) -> result_paged(metric_filters()).
describe_metric_filters(#aws_config{} = Config) ->
describe_metric_filters(undefined, Config);
describe_metric_filters(LogGroupName) ->
describe_metric_filters(LogGroupName, default_config()).
-spec describe_metric_filters(
log_group_name(),
aws_config()
) -> result_paged(metric_filters()).
describe_metric_filters(LogGroupName, Config) ->
describe_metric_filters(LogGroupName, ?DEFAULT_LIMIT, Config).
-spec describe_metric_filters(
log_group_name(),
limit(),
aws_config()
) -> result_paged(metric_filters()).
describe_metric_filters(LogGroupName, Limit, Config) ->
describe_metric_filters(LogGroupName, Limit, undefined, Config).
-spec describe_metric_filters(
log_group_name(),
limit(),
filter_name_prefix(),
aws_config()
) -> result_paged(metric_filters()).
describe_metric_filters(LogGroupName, Limit, FilterNamePrefix, Config) ->
describe_metric_filters(LogGroupName, Limit, FilterNamePrefix, undefined,
undefined, Config).
-spec describe_metric_filters(
log_group_name(),
limit(),
filter_name_prefix(),
metric_name(),
metric_namespace(),
aws_config()
) -> result_paged(metric_filters()).
describe_metric_filters(LogGroupName, Limit, FilterNamePrefix, MetricName,
MetricNamespace, Config) ->
describe_metric_filters(LogGroupName, Limit, FilterNamePrefix, MetricName,
MetricNamespace, undefined, Config).
-spec describe_metric_filters(
log_group_name(),
limit(),
filter_name_prefix(),
metric_name(),
metric_namespace(),
paging_token(),
aws_config()
) -> result_paged(metric_filters()).
describe_metric_filters(LogGroupName, Limit, FilterNamePrefix, MetricName,
MetricNamespace, PrevToken, Config) ->
case cw_request(Config, "DescribeMetricFilters", [
{<<"logGroupName">>, LogGroupName},
{<<"limit">>, Limit},
{<<"filterNamePrefix">>, FilterNamePrefix},
{<<"metricName">>, MetricName},
{<<"metricNamespace">>, MetricNamespace},
{<<"nextToken">>, PrevToken}
]) of
{ok, Data} ->
MetricFilters = proplists:get_value(<<"metricFilters">>, Data, []),
NextToken = proplists:get_value(<<"nextToken">>, Data, undefined),
{ok, MetricFilters, NextToken};
{error, Reason} ->
{error, Reason}
end.
%%------------------------------------------------------------------------------
%% @doc
%%
%% ListTagsLogGroup
%% https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_ListTagsLogGroup.html
%%
%% @end
%%------------------------------------------------------------------------------
-spec list_tags_log_group(
log_group_name()
) -> tags_return().
list_tags_log_group(LogGroup) ->
list_tags_log_group(LogGroup, default_config()).
-spec list_tags_log_group(
log_group_name(),
aws_config()
) -> tags_return().
list_tags_log_group(LogGroup, Config) ->
case
cw_request(Config, "ListTagsLogGroup", [{<<"logGroupName">>, LogGroup}])
of
{ok, Json} ->
Tags = proplists:get_value(<<"tags">>, Json, []),
{ok, Tags};
{error, _} = Error ->
Error
end.
%%------------------------------------------------------------------------------
%% @doc
%%
%% TagLogGroup action
%% https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_TagLogGroup.html
%%
%% @end
%%------------------------------------------------------------------------------
-spec tag_log_group(
log_group_name(),
list(tag())
) -> {ok, []}
| {ok, jsx:json_term()}
| {error, erlcloud_aws:httpc_result_error()}.
tag_log_group(LogGroup, Tags) when is_list(Tags) ->
tag_log_group(LogGroup, Tags, default_config()).
-spec tag_log_group(
log_group_name(),
list(tag()),
aws_config()
) -> {ok, []}
| {ok, jsx:json_term()}
| {error, erlcloud_aws:httpc_result_error()}.
tag_log_group(LogGroup, Tags, Config) when is_list(Tags) ->
Params = [{<<"logGroupName">>, LogGroup},
{<<"tags">>, Tags}
],
cw_request(Config, "TagLogGroup", Params).
%%==============================================================================
%% Internal functions
%%==============================================================================
default_config() ->
erlcloud_aws:default_config().
cw_request(Config, Action, Params) ->
maybe_cw_request(erlcloud_aws:update_config(Config), Action, Params).
maybe_cw_request({ok, Config}, Action, Params) ->
Request = make_request_body(Action, Params),
maybe_json(
erlcloud_aws:aws_request_form_raw(
post,
Config#aws_config.cloudwatch_logs_scheme,
Config#aws_config.cloudwatch_logs_host,
Config#aws_config.cloudwatch_logs_port,
"/",
Request,
make_request_headers(Config, Action, Request),
Config
)
);
maybe_cw_request({error, _} = Error, _Action, _Params) ->
Error.
maybe_json({ok, <<>>}) ->
{ok, []};
maybe_json({ok, Response}) ->
{ok, jsx:decode(Response, [{return_maps, false}])};
maybe_json({error, _} = Error) ->
Error.
make_request_headers(Config, Action, Body) ->
lists:append(make_signed_headers(Config, Action, Body), ?DEFAULT_HEADERS).
make_signed_headers(Config, Action, Body) ->
#aws_config{cloudwatch_logs_host = Host} = Config,
Target = lists:append([?API_PREFIX, ".", Action]),
Headers = [{"host", Host}, {"x-amz-target", Target}],
Region = erlcloud_aws:aws_region_from_host(Host),
erlcloud_aws:sign_v4_headers(Config, Headers, Body, Region, ?SERVICE_NAME).
make_request_body(Action, RequestParams) ->
DefaultParams = [{<<"Action">>, Action}, {<<"Version">>, ?API_VERSION}],
Params = lists:append(DefaultParams, RequestParams),
jsx:encode(prepare_request_params(Params)).
prepare_request_params(Params) ->
lists:filtermap(fun prepare_request_param/1, Params).
prepare_request_param({_Key, undefined}) ->
false;
prepare_request_param({Key, [H | _] = Value})
when is_integer(H) ->
{true, {Key, list_to_binary(Value)}};
prepare_request_param({Key, Value}) ->
{true, {Key, Value}}.