Packages
erlcloud
3.1.9
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 log_stream_order() :: log_stream_name | last_event_time | undefined.
-type events() :: [#{message => binary(), timestamp => pos_integer()}].
-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().
%% Library initialization
-export([
configure/2,
configure/3,
new/2,
new/3
]).
%% CloudWatch API
-export([
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,
put_logs_events/4,
put_logs_events/5
]).
%%==============================================================================
%% 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
%%
%% 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()
) -> datum:either( seq_token() ).
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()
) -> datum:either( seq_token() ).
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].
%%==============================================================================
%% 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, Response}) ->
{ok, jsx:decode(Response)};
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}}.