Skip to content

Commit e3db176

Browse files
authored
Merge pull request #2 from opencensus-beam/setup-circle-ci
Setup Circle CI
2 parents 982db73 + d781584 commit e3db176

File tree

9 files changed

+268
-23
lines changed

9 files changed

+268
-23
lines changed

.circleci/config.yml

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
version: 2.1
2+
3+
commands:
4+
fetch_deps:
5+
description: "Fetch deps, build, and cache them"
6+
parameters:
7+
otp_version:
8+
type: string
9+
default: "any"
10+
steps:
11+
- restore_cache:
12+
keys:
13+
- deps-v1-<<parameters.otp_version>>-{{ checksum "rebar.lock" }}-{{ .Branch }}-{{ .Revision }}
14+
- deps-v1-<<parameters.otp_version>>-{{ checksum "rebar.lock" }}-{{ .Branch }}-
15+
- deps-v1-<<parameters.otp_version>>-{{ checksum "rebar.lock" }}-
16+
- deps-v1-<<parameters.otp_version>>-
17+
- run: rebar3 get-deps
18+
- run: rebar3 as test compile --deps_only
19+
- save_cache:
20+
key: deps-v1-{{ .Branch }}-{{ .Revision }}
21+
paths:
22+
- "~/.cache/rebar3/hex/default/packages"
23+
- "_build/test/lib"
24+
25+
jobs:
26+
test:
27+
parameters:
28+
otp_version:
29+
type: string
30+
description: OTP version to test against to
31+
docker:
32+
- image: erlang:<<parameters.otp_version>>
33+
working_directory: ~/repo
34+
steps:
35+
- checkout
36+
- fetch_deps:
37+
otp_version: <<parameters.otp_version>>
38+
- run: mkdir -p /tmp/ct_reports
39+
- run: rebar3 do ct --cover, cover
40+
- run: rebar3 covertool generate
41+
- run: bash <(curl -s https://codecov.io/bash) -f _build/test/covertool/*.xml
42+
- store_test_results:
43+
path: /tmp/ct_reports
44+
45+
dialyzer:
46+
docker:
47+
- image: erlang:21
48+
working_directory: ~/repo
49+
steps:
50+
- checkout
51+
- fetch_deps
52+
- restore_cache:
53+
keys:
54+
- dialyzer-v1-{{ checksum "rebar.lock" }}
55+
- dialyzer-v1
56+
- run: rebar3 dialyzer
57+
- save_cache:
58+
key: dialyzer-v1-{{ checksum "rebar.lock" }}
59+
paths:
60+
- "_build"
61+
- run: rebar3 dialyzer
62+
63+
format:
64+
docker:
65+
- image: erlang:21
66+
working_directory: ~/repo
67+
steps:
68+
- checkout
69+
- fetch_deps
70+
- run: rebar3 lint
71+
72+
workflows:
73+
version: 2
74+
lints:
75+
jobs:
76+
- dialyzer
77+
- format
78+
# - inchci
79+
testing:
80+
jobs:
81+
- test:
82+
name: "OTP 21"
83+
otp_version: "21"
84+
- test:
85+
name: "OTP 20"
86+
otp_version: "20"

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
oc_datadog
22
=====
33

4+
[![CircleCI](https://circleci.com/gh/opencensus-beam/opencensus_datadog.svg?style=svg)](https://circleci.com/gh/opencensus-beam/opencensus_datadog)
5+
[![codecov](https://codecov.io/gh/opencensus-beam/opencensus_datadog/branch/master/graph/badge.svg)](https://codecov.io/gh/opencensus-beam/opencensus_datadog)
6+
47
[Opencensus][oc] integration to [DataDog][dd] traces and metrics (via dogstatsd).
58

69
## Installation

config/dev.conf

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
[
2-
{opencensus, [
3-
{reporter, {oc_reporter_datadog, []}},
4-
{stat, [
5-
{exporters, [{oc_stat_exporter_datadog, []}]}
6-
]}
7-
]}
2+
{opencensus,
3+
[{reporter, {oc_reporter_datadog, []}},
4+
{stat, [{exporters, [{oc_stat_exporter_datadog, []}]}]}]}
85
].

rebar.config

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
{erl_opts, [debug_info]}.
2-
{deps, [{opencensus, "~> 0.6.0"},
2+
{deps, [{opencensus, "~> 0.7.0"},
33
{jsx, "~> 2.9"}]}.
44

55
{project_plugins, [rebar3_lint,
66
covertool]}.
77

88
{shell, [{config, "config/dev.conf"}]}.
99

10+
{eunit_opts, [{report, {eunit_surefire, [{dir, "."}]}}]}.
11+
{ct_opts, [{ct_hooks, [{cth_surefire, [{path, "/tmp/ct_reports/report.xml"}]}]}]}.
12+
1013
% vi: ft=erlang syn=erlang

rebar.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22
[{<<"counters">>,{pkg,<<"counters">>,<<"0.2.1">>},1},
33
{<<"ctx">>,{pkg,<<"ctx">>,<<"0.5.0">>},1},
44
{<<"jsx">>,{pkg,<<"jsx">>,<<"2.9.0">>},0},
5-
{<<"opencensus">>,{pkg,<<"opencensus">>,<<"0.6.0">>},0},
5+
{<<"opencensus">>,{pkg,<<"opencensus">>,<<"0.7.0">>},0},
66
{<<"rfc3339">>,{pkg,<<"rfc3339">>,<<"0.9.0">>},2},
77
{<<"wts">>,{pkg,<<"wts">>,<<"0.3.0">>},1}]}.
88
[
99
{pkg_hash,[
1010
{<<"counters">>, <<"AA3D97E88F92573488987193D0F48EFCE0F3B2CD1443BF4EE760BC7F99322F0C">>},
1111
{<<"ctx">>, <<"78E0F16712E12D707A7F34277381B8E193D7C71EAA24D37330DC02477C09EDA5">>},
1212
{<<"jsx">>, <<"D2F6E5F069C00266CAD52FB15D87C428579EA4D7D73A33669E12679E203329DD">>},
13-
{<<"opencensus">>, <<"90C1078A3BA18817D6445B3F79E7515122823198FEDD5A880F74D69C205D8B90">>},
13+
{<<"opencensus">>, <<"B4C5F6A96F2BA2154570F24BB08B65D6EE0FF5B61518ACF706CA760B7696A4E1">>},
1414
{<<"rfc3339">>, <<"2075653DC9407541C84B1E15F8BDA2ABE95FB17C9694025E079583F2D19C1060">>},
1515
{<<"wts">>, <<"5CDF22C775CB1EBAE24C326A5DB6074D753C42F4BD12A9AA47CC62D3E2C71AD1">>}]}
1616
].

src/oc_reporter_datadog.erl

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,12 @@
1717
-export([init/1, report/2]).
1818

1919
-include_lib("opencensus/include/opencensus.hrl").
20+
21+
-ifdef(OTP_RELEASE).
2022
-include_lib("kernel/include/logger.hrl").
23+
-else.
24+
-define(LOG_ERROR(Format, Data), error_logger:error_msg(Format, Data)).
25+
-endif.
2126

2227
-define(TRACER_VERSION, "OC/0.1.0").
2328

@@ -32,14 +37,20 @@ init(Options) ->
3237
Port = proplists:get_value(port, Options, ?DEFAULT_PORT),
3338
Service = proplists:get_value(service, Options, ?DEFAULT_SERVICE),
3439
Type = proplists:get_value(type, Options, ?DEFAULT_TYPE),
35-
#{host => Host, port => Port, service => Service, type => Type}.
40+
Client = proplists:get_value(http_client, Options, fun default_client/3),
41+
#{host => Host,
42+
port => Port,
43+
service => Service,
44+
type => Type,
45+
client => Client}.
3646

3747
-spec report(nonempty_list(opencensus:span()), oc_reporter:opts()) -> ok.
3848
report(Spans, #{
3949
service := Service,
4050
host := Host,
4151
port := Port,
42-
type := Type}) ->
52+
type := Type,
53+
client := Client}) ->
4354
Sorted = lists:sort(fun(A, B) ->
4455
A#span.trace_id =< B#span.trace_id
4556
end, Spans),
@@ -55,15 +66,9 @@ report(Spans, #{
5566
{"Datadog-Meta-Lang-Interpreter", interpreter_version()},
5667
{"Datadog-Meta-Tracer-Version", ?TRACER_VERSION}
5768
],
58-
case httpc:request(
59-
put,
60-
{Address, Headers, "application/json", JSON},
61-
[],
62-
[]
63-
) of
64-
{ok, {{_, Code, _}, _, _}} when Code >= 200, Code =< 299 ->
65-
ok;
66-
{ok, {{_, Code, _}, _, Message}} ->
69+
case Client(Address, Headers, JSON) of
70+
ok -> ok;
71+
{error, {http_error, Code, Message}} ->
6772
?LOG_ERROR("DD: Unable to send spans,"
6873
" DD reported an error: ~p: ~p",
6974
[Code, Message]);
@@ -76,8 +81,23 @@ report(Spans, #{
7681
?LOG_ERROR("DD: Can't spans encode to json: ~p", [Error])
7782
end.
7883

84+
default_client(Address, Headers, JSON) ->
85+
case httpc:request(
86+
put,
87+
{Address, Headers, "application/json", JSON},
88+
[],
89+
[]
90+
) of
91+
{ok, {{_, Code, _}, _, _}} when Code >= 200, Code =< 299 ->
92+
ok;
93+
{ok, {{_, Code, _}, _, Body}} ->
94+
{error, {http_error, Code, Body}};
95+
{error, Reason} ->
96+
{error, Reason}
97+
end.
98+
7999
lang_version() ->
80-
erlang:system_info(otp_version).
100+
erlang:system_info(otp_release).
81101

82102
interpreter_version() ->
83103
io_lib:format('~s-~s', [erlang:system_info(version),

src/oc_stat_exporter_datadog.erl

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@
1919
-define(DEFAULT_HOST, "localhost").
2020
-define(DEFAULT_PORT, 8125).
2121

22+
-ifdef(OTP_RELEASE).
2223
-include_lib("kernel/include/logger.hrl").
24+
-else.
25+
-define(LOG_ERROR(Format, Data), error_logger:error_msg(Format, Data)).
26+
-endif.
2327

2428
export(ViewData, Options) ->
2529
Host = proplists:get_value(host, Options, ?DEFAULT_HOST),
@@ -43,9 +47,11 @@ build_packet(#{name := Name,
4347
lists:join($\n, List).
4448

4549
build_tags(Tags, TagsV, CTags) ->
46-
build_tags(maps:merge(CTags, maps:from_list(lists:zip(Tags, TagsV)))).
50+
TagsMap = maps:merge(CTags, maps:from_list(lists:zip(Tags, TagsV))),
51+
TagsList = maps:to_list(TagsMap),
52+
Cleaned = [{Key, Value} || {Key, Value} <- TagsList, Value =/= undefined],
53+
build_tags(Cleaned).
4754

48-
build_tags(Map) when is_map(Map) -> build_tags(maps:to_list(Map));
4955
build_tags([]) -> [];
5056
build_tags(Tags) ->
5157
List = [[to_key(Key), $:, Value]

test/oc_reporter_datadog_SUITE.erl

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
-module(oc_reporter_datadog_SUITE).
2+
3+
-include_lib("opencensus/include/opencensus.hrl").
4+
-include_lib("common_test/include/ct.hrl").
5+
-include_lib("eunit/include/eunit.hrl").
6+
7+
-export([all/0, init_per_testcase/2]).
8+
-export([test_eunit/1, test_reports_spans/1]).
9+
10+
all() -> [test_eunit, test_reports_spans].
11+
12+
init_per_testcase(_, Config) ->
13+
Span = #span{
14+
name = <<"foo">>,
15+
trace_id = 1,
16+
span_id = 1,
17+
start_time = wts:timestamp(),
18+
end_time = wts:timestamp(),
19+
attributes = #{foo => "bar"}
20+
},
21+
Options = oc_reporter_datadog:init([{http_client, fun mock_client/3}]),
22+
[{span, Span}, {options, Options} | Config].
23+
24+
mock_client(Address, Headers, JSON) ->
25+
self() ! {http, lists:flatten(Address), Headers, JSON},
26+
ok.
27+
28+
test_reports_spans(Config) ->
29+
Options = ?config(options, Config),
30+
Span = ?config(span, Config),
31+
oc_reporter_datadog:report([Span], Options),
32+
receive
33+
{http, "http://localhost:8126/v0.3/traces", _, JSON} ->
34+
Data = jsx:decode(JSON, [return_maps]),
35+
[[RSpan]] = Data,
36+
#{<<"name">> := <<"foo">>,
37+
<<"trace_id">> := 1,
38+
<<"span_id">> := 1,
39+
<<"type">> := <<"custom">>,
40+
<<"duration">> := _,
41+
<<"meta">> := #{<<"foo">> := <<"bar">>}} = RSpan,
42+
ok;
43+
Msg ->
44+
ct:fail("Unknown message: ~p", [Msg])
45+
after
46+
1000 -> ct:fail("Didn't received message in 1s")
47+
end.
48+
49+
%% EUNIT TESTS =================================================================
50+
51+
test_eunit(_Config) -> eunit:test(?MODULE, []).
52+
53+
init_return_value_contains_needed_keys_test_() ->
54+
Opts = oc_reporter_datadog:init([]),
55+
{"test that init value contains needed keys", inparallel,
56+
[?_assert(maps:is_key(service, Opts)),
57+
?_assert(maps:is_key(host, Opts)),
58+
?_assert(maps:is_key(port, Opts)),
59+
?_assert(maps:is_key(type, Opts))]}.
60+
61+
init_sets_proper_fields_to_requested_values_test_() ->
62+
{"test that init sets proper fields in resulting map", inparallel,
63+
[init_sets(host, "foo"),
64+
init_sets(port, 6666),
65+
init_sets(service, "foo"),
66+
init_sets(type, "foo")]}.
67+
68+
init_sets(Key, Value) ->
69+
Opts = oc_reporter_datadog:init([{Key, Value}]),
70+
?_assertEqual(Value, maps:get(Key, Opts)).
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
-module(oc_stat_exporter_datadog_SUITE).
2+
3+
-include_lib("common_test/include/ct.hrl").
4+
-include_lib("eunit/include/eunit.hrl").
5+
6+
-export([all/0, init_per_testcase/2, end_per_testcase/2]).
7+
-export([test_eunit/1, test_export/1, test_export_with_tags/1]).
8+
9+
all() -> [test_eunit, test_export, test_export_with_tags].
10+
11+
init_per_testcase(test_eunit, Config) -> Config;
12+
init_per_testcase(_, Config) ->
13+
_ = application:ensure_all_started(oc_datadog),
14+
{ok, Socket} = gen_udp:open(8125, [{active, once}]),
15+
Measure = oc_stat_measure:new('datadog/test', "Test", foos),
16+
{ok, View} = oc_stat_view:subscribe(#{
17+
name => "datadog.test",
18+
measure => Measure,
19+
description => "Test",
20+
tags => [foo, bar],
21+
aggregation => oc_stat_aggregation_count}),
22+
[{udp, Socket}, {measure, Measure}, {view, View} | Config].
23+
24+
end_per_testcase(test_eunit, Config) -> Config;
25+
end_per_testcase(_, Config) ->
26+
Socket = ?config(udp, Config),
27+
View = ?config(view, Config),
28+
oc_stat_view:unsubscribe(View),
29+
oc_stat_view:deregister(View),
30+
gen_udp:close(Socket),
31+
Config.
32+
33+
test_eunit(_Config) -> eunit:test(?MODULE, []).
34+
35+
test_export(Config) ->
36+
_ = oc_stat:record(#{}, 'datadog/test', 1),
37+
View = ?config(view, Config),
38+
Data = oc_stat_view:export(View),
39+
oc_stat_exporter_datadog:export([Data], []),
40+
receive
41+
{udp, _, _, _, "datadog.test:1|g"} -> ok;
42+
Msg ->
43+
ct:fail("Unknown message: ~p", [Msg])
44+
after
45+
1000 -> ct:fail("Didn't received message in 1s")
46+
end.
47+
48+
test_export_with_tags(Config) ->
49+
_ = oc_stat:record(#{foo => "1", bar => "2"}, 'datadog/test', 1),
50+
View = ?config(view, Config),
51+
Data = oc_stat_view:export(View),
52+
oc_stat_exporter_datadog:export([Data], []),
53+
receive
54+
{udp, _, _, _, "datadog.test:1|g|#bar:2,foo:1"} -> ok;
55+
{udp, _, _, _, "datadog.test:1|g|#foo:1,bar:2"} -> ok;
56+
Msg ->
57+
ct:fail("Unknown message: ~p", [Msg])
58+
after
59+
1000 -> ct:fail("Didn't received message in 1s")
60+
end.

0 commit comments

Comments
 (0)