buildkite-trace 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 0abdf59a8b25b2e696d5d05d5d3710df8e251f553e0cdaf245a17defae0cea06
4
+ data.tar.gz: c5b92901cd2428a65cbabb494bcef17347818f6768f80d2ea42f14c22ef52311
5
+ SHA512:
6
+ metadata.gz: 393328b187032c748ecb7d9a393ad2eeec7393d18ed226e0bf5987dd8be3747afbfe99396d23da2232fada8649c72e9c94c8e1ae3be346383015162bc08f4bb6
7
+ data.tar.gz: c8c0f9a4052728b2eb3152fbfa0169dbdfa17e29eff93e5d29b9833a39df976cf91ab8e43ddb54c15b74b83454f3e3bdde61b0051a29213f031825beb254f3d8
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2019 James Healy
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a 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,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,78 @@
1
+ ## buildkite-trace
2
+
3
+ If you want to get your build time under control, first you need to measure it.
4
+
5
+ This is a mini rack app that accepts buildkite webhooks and submits them to a datadog agent as traces.
6
+
7
+ The traces become available in the datadog web UI, and look something like this:
8
+
9
+ ![Build waterfall](images/build-waterfall.png)
10
+
11
+ The spans in the trace also generate metrics that can be used in dashboards and monitors:
12
+
13
+ ![Build chart](images/build-chart.png)
14
+
15
+ ### Usage
16
+
17
+ Begin by adding buildkite-trace to your `Gemfile`.
18
+
19
+ gem "buildite-trace"
20
+
21
+ Then create a `config.ru` file in the same directory, with the following content:
22
+
23
+ require 'buildkite-trace'
24
+ run Buildkite::Trace::App
25
+
26
+ Finally, run this:
27
+
28
+ bundle exec rackup
29
+
30
+ If you have an alternative method of running rack apps, that should work fine
31
+ too. A popular option is puma - add it to your Gemfile (`gem "puma"`), and
32
+ start the server with:
33
+
34
+ bundle exec puma
35
+
36
+ ### Deployment
37
+
38
+ The app should be deployed to a public webserver somewhere, with a domain name
39
+ and (ideally) TLS enabled.
40
+
41
+ Once deployed, use the web UI on buildkite.com to send webhooks to:
42
+
43
+ https://yourdomain.example.com/events
44
+
45
+ In the webhook settings on buildkite.com, enable at least the following events:
46
+
47
+ * `build.finished`
48
+ * `job.finished`
49
+
50
+ The deployed service must have access to an instance of the datadog agent. Each
51
+ time it receives a webhook from buildkite, it'll translate it into trace data
52
+ that's sent to the datadog agent at `http://<dd-agent-ip>:8126/`
53
+
54
+ ### Configuration
55
+
56
+ There is only one configurable value at this stage - the IP or hostname of the
57
+ datadog agent. To override the default (`127.0.0.1`) set the
58
+ `DATADOG_AGENT_HOST_IP` ENV var.
59
+
60
+ ### Developing
61
+
62
+ I typically use docker to setup a consistent development. You can start a
63
+ development server like this:
64
+
65
+ ./auto/start
66
+
67
+ ... and post sample webhooks to it:
68
+
69
+ curl -v --data @spec/fixtures/buildkite_job_finished.json http://127.0.0.1:9393/events
70
+ curl -v --data @spec/fixtures/buildkite_build_finished.json http://127.0.0.1:9393/events
71
+
72
+ You'll need to have a datadog agent listening for traces on
73
+ http://127.0.0.1:8126, or you'll get a "Errno::ECONNREFUSED: Failed to open TCP
74
+ connection to 127.0.0.1:8126" exception.
75
+
76
+ To run the tests:
77
+
78
+ ./auto/test
Binary file
@@ -0,0 +1,7 @@
1
+ require 'buildkite/trace/build_finished_event'
2
+ require 'buildkite/trace/job_finished_event'
3
+ require 'buildkite/trace/unknown_event'
4
+ require 'buildkite/trace/event'
5
+ require 'buildkite/trace/span'
6
+ require 'buildkite/trace/app'
7
+ require 'buildkite/trace/client'
@@ -0,0 +1,31 @@
1
+ require 'sinatra/base'
2
+ require 'buildkite/trace/event'
3
+ require 'buildkite/trace/client'
4
+
5
+ module Buildkite
6
+ module Trace
7
+ class App < Sinatra::Application
8
+ get '/' do
9
+ 'Buildkite Trace Server'
10
+ end
11
+
12
+ post '/events' do
13
+ request.body.rewind
14
+ data = request.body.read
15
+ event = Buildkite::Trace::Event.build(data)
16
+ span = event.to_span
17
+ if span
18
+ puts span.to_hash.inspect
19
+ trace_client = Buildkite::Trace::Client.new(datadog_hostname)
20
+ trace_client.submit_trace([span.to_hash])
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def datadog_hostname
27
+ ENV.fetch("DATADOG_AGENT_HOST_IP", "127.0.0.1")
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,82 @@
1
+ require 'date'
2
+ require 'buildkite/trace/span'
3
+ require 'digest/crc64'
4
+
5
+ module Buildkite
6
+ module Trace
7
+
8
+ # Value object that wraps raw buildkite webhook data and provides convenience
9
+ # methods for querying it
10
+ class BuildFinishedEvent
11
+ def initialize(data)
12
+ @data = data
13
+ end
14
+
15
+ def name
16
+ @data.fetch("event", "")
17
+ end
18
+
19
+ def pipeline_name
20
+ @data.fetch("pipeline", {}).fetch("name", "")
21
+ end
22
+
23
+ def pipeline_slug
24
+ @data.fetch("pipeline", {}).fetch("slug", "")
25
+ end
26
+
27
+ def build_id
28
+ @data.fetch("build", {}).fetch("id", "")
29
+ end
30
+
31
+ def build_web_url
32
+ @data.fetch("build", {}).fetch("web_url", "")
33
+ end
34
+
35
+ def passed?
36
+ @data.fetch("build", {}).fetch("state", "") == "passed"
37
+ end
38
+
39
+ def build_branch
40
+ @data.fetch("build", {}).fetch("branch", "")
41
+ end
42
+
43
+ def build_created_at
44
+ value = @data.fetch("build", {}).fetch("created_at", nil)
45
+ value ? DateTime.parse(value).to_time : nil
46
+ end
47
+
48
+ def build_started_at
49
+ value = @data.fetch("build", {}).fetch("started_at", nil)
50
+ value ? DateTime.parse(value).to_time : nil
51
+ end
52
+
53
+ def build_finished_at
54
+ value = @data.fetch("build", {}).fetch("finished_at", nil)
55
+ value ? DateTime.parse(value).to_time : nil
56
+ end
57
+
58
+ def to_span
59
+ Span.new(
60
+ trace_id: Digest::CRC64.checksum(build_id),
61
+ span_id: Digest::CRC64.checksum(build_id) + 1,
62
+ parent_id: nil,
63
+ name: "build",
64
+ resource: pipeline_slug,
65
+ service: "buildkite",
66
+ type: "custom",
67
+ start: build_started_at.to_i * 1_000_000_000,
68
+ duration: duration_in_secs * 1_000_000_000,
69
+ metrics: {_sampling_priority_v1: 2},
70
+ meta: {url: build_web_url, pipeline: pipeline_slug},
71
+ )
72
+ end
73
+
74
+ private
75
+
76
+ def duration_in_secs
77
+ build_finished_at.to_i - build_started_at.to_i
78
+ end
79
+
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,22 @@
1
+ require 'net/http'
2
+
3
+ module Buildkite
4
+ module Trace
5
+ class Client
6
+ def initialize(hostname)
7
+ @uri = URI("http://#{hostname}:8126/v0.3/traces")
8
+ end
9
+
10
+ def submit_trace(array_of_spans)
11
+ array_of_traces = [array_of_spans]
12
+ http = Net::HTTP.new(@uri.host, 8126)
13
+ response = http.start do |http|
14
+ request = Net::HTTP::Put.new(@uri.request_uri, { 'Content-Type' => 'application/json'})
15
+ request.body = JSON.dump(array_of_traces)
16
+ http.request(request)
17
+ end
18
+ response.code.to_i == 200
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,24 @@
1
+ require 'buildkite/trace/build_finished_event'
2
+ require 'buildkite/trace/unknown_event'
3
+ require 'json'
4
+
5
+ module Buildkite
6
+ module Trace
7
+ class Event
8
+ def self.build(string)
9
+ data = JSON.load(string)
10
+
11
+ case data.fetch("event", "")
12
+ when "build.finished" then
13
+ BuildFinishedEvent.new(data)
14
+ when "job.finished" then
15
+ JobFinishedEvent.new(data)
16
+ else
17
+ UnknownEvent.new(data)
18
+ end
19
+ rescue JSON::ParserError
20
+ UnknownEvent.new("event" => "error", "message" => "Invalid JSON", "body" => string)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,106 @@
1
+ require 'date'
2
+ require 'buildkite/trace/span'
3
+ require 'digest/crc64'
4
+
5
+ module Buildkite
6
+ module Trace
7
+ # Value object that wraps raw buildkite webhook data and provides convenience
8
+ # methods for querying it
9
+ class JobFinishedEvent
10
+ def initialize(data)
11
+ @data = data
12
+ end
13
+
14
+ def name
15
+ @data.fetch("event", "")
16
+ end
17
+
18
+ def job_id
19
+ @data.fetch("job", {}).fetch("id","")
20
+ end
21
+
22
+ def job_name
23
+ @data.fetch("job", {}).fetch("name","")
24
+ end
25
+
26
+ def job_slug
27
+ slugorize(job_name)
28
+ end
29
+
30
+ def job_state
31
+ @data.fetch("job", {}).fetch("state","")
32
+ end
33
+
34
+ def job_web_url
35
+ @data.fetch("job", {}).fetch("web_url","")
36
+ end
37
+
38
+ def job_started_at
39
+ value = @data.fetch("job", {}).fetch("started_at", nil)
40
+ value ? DateTime.parse(value).to_time : nil
41
+ end
42
+
43
+ def job_finished_at
44
+ value = @data.fetch("job", {}).fetch("finished_at", nil)
45
+ value ? DateTime.parse(value).to_time : nil
46
+ end
47
+
48
+ def agent_name
49
+ @data.fetch("job", {}).fetch("agent",{}).fetch("name","")
50
+ end
51
+
52
+ def agent_hostname
53
+ @data.fetch("job", {}).fetch("agent",{}).fetch("hostname","")
54
+ end
55
+
56
+ def build_id
57
+ @data.fetch("build", {}).fetch("id","")
58
+ end
59
+
60
+ def build_branch
61
+ @data.fetch("build", {}).fetch("branch","")
62
+ end
63
+
64
+ def pipeline_name
65
+ @data.fetch("pipeline", {}).fetch("name", "")
66
+ end
67
+
68
+ def pipeline_slug
69
+ @data.fetch("pipeline", {}).fetch("slug", "")
70
+ end
71
+
72
+ def to_span
73
+ Span.new(
74
+ trace_id: Digest::CRC64.checksum(build_id),
75
+ span_id: Digest::CRC64.checksum(job_id),
76
+ parent_id: Digest::CRC64.checksum(build_id) + 1,
77
+ name: "build.job",
78
+ resource: job_name,
79
+ service: "buildkite",
80
+ type: "custom",
81
+ start: job_started_at.to_i * 1_000_000_000,
82
+ duration: duration_in_secs * 1_000_000_000,
83
+ metrics: {_sampling_priority_v1: 2},
84
+ meta: {url: job_web_url, pipeline: pipeline_slug},
85
+ )
86
+ end
87
+
88
+ private
89
+
90
+ def duration_in_secs
91
+ job_finished_at.to_i - job_started_at.to_i
92
+ end
93
+
94
+ def slugorize(input)
95
+ result = input.to_s.downcase
96
+ result.gsub!(/['|’]/, '') # Remove apostrophes
97
+ result.gsub!('&', 'and') # Replace & with 'and'
98
+ result.gsub!(/[^a-z0-9\-]/, '-') # Get rid of anything we don't like
99
+ result.gsub!(/-+/, '-') # collapse dashes
100
+ result.gsub!(/-$/, '') # trim dashes
101
+ result.gsub!(/^-/, '') # trim dashes
102
+ result
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,40 @@
1
+ module Buildkite
2
+ module Trace
3
+ # A value object to hold the data we will submit to datadog
4
+ class Span
5
+ attr_reader :trace_id, :span_id, :parent_id, :name, :resource
6
+ attr_reader :service, :type, :start, :duration, :metrics, :meta
7
+
8
+ def initialize(trace_id:, span_id:, parent_id:, name:, resource:, service:, type:, start:, duration:, metrics:, meta:)
9
+ @trace_id = trace_id
10
+ @span_id = span_id
11
+ @parent_id = parent_id
12
+ @name = name
13
+ @resource = resource
14
+ @service = service
15
+ @type = type
16
+ @start = start
17
+ @duration = duration
18
+ @metrics = metrics
19
+ @meta = meta
20
+ end
21
+
22
+ def to_hash
23
+ {
24
+ trace_id: trace_id,
25
+ span_id: span_id,
26
+ parent_id: parent_id,
27
+ name: name,
28
+ resource: resource,
29
+ service: service,
30
+ type: @type,
31
+ start: start,
32
+ duration: duration,
33
+ metrics: metrics,
34
+ meta: meta,
35
+ }
36
+ end
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,18 @@
1
+ module Buildkite
2
+ module Trace
3
+ class UnknownEvent
4
+ def initialize(data)
5
+ @data = data
6
+ end
7
+
8
+ def name
9
+ @data.fetch("event", "")
10
+ end
11
+
12
+ def to_span
13
+ nil
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,85 @@
1
+ require 'json'
2
+
3
+ describe Buildkite::Trace::BuildFinishedEvent do
4
+ let(:json_path) { File.join(File.dirname(__FILE__), "..", "..", "fixtures", "buildkite_build_finished.json")}
5
+ let(:json) { JSON.load(File.read(json_path)) }
6
+ let(:event) { Buildkite::Trace::BuildFinishedEvent.new(json)}
7
+
8
+ describe '.name' do
9
+ it "returns the correct value" do
10
+ expect(event.name).to eq "build.finished"
11
+ end
12
+ end
13
+
14
+ describe '.build_id' do
15
+ it "returns the correct value" do
16
+ expect(event.build_id).to eq "83636ec4-0643-4d4b-9576-4b4cc9416dbc"
17
+ end
18
+ end
19
+
20
+ describe '.build_branch' do
21
+ it "returns the branch name" do
22
+ expect(event.build_branch).to eq "master"
23
+ end
24
+ end
25
+
26
+ describe '.pipeline_name' do
27
+ it "returns the pipeline name" do
28
+ expect(event.pipeline_name).to eq "Bar"
29
+ end
30
+ end
31
+
32
+ describe '.pipeline_slug' do
33
+ it "returns the pipeline name" do
34
+ expect(event.pipeline_slug).to eq "bar"
35
+ end
36
+ end
37
+
38
+ describe '.build_web_url' do
39
+ it "returns with the build web_url" do
40
+ expect(event.build_web_url).to eq "https://buildkite.com/foo/bar/builds/4472"
41
+ end
42
+ end
43
+
44
+ describe '.passed?' do
45
+ it "returns false" do
46
+ expect(event.passed?).to eq false
47
+ end
48
+ end
49
+
50
+ describe 'build_created_at' do
51
+ it "returns correct time" do
52
+ expect(event.build_created_at).to eq Time.utc(2018,12,28,13,3,28)
53
+ end
54
+ end
55
+
56
+ describe 'build_started_at' do
57
+ it "returns correct time" do
58
+ expect(event.build_started_at).to eq Time.utc(2018,12,28,13,3,32)
59
+ end
60
+ end
61
+
62
+ describe 'build_finished_at' do
63
+ it "returns correct time" do
64
+ expect(event.build_finished_at).to eq Time.utc(2018,12,28,13,29,38)
65
+ end
66
+ end
67
+
68
+ describe '.to_span' do
69
+ let(:span) { event.to_span }
70
+
71
+ it "returns a Span instance with the correct values" do
72
+ expect(span.trace_id).to eq(18259648613135438764)
73
+ expect(span.span_id).to eq(18259648613135438765)
74
+ expect(span.parent_id).to be_nil
75
+ expect(span.name).to eq("build")
76
+ expect(span.resource).to eq("bar")
77
+ expect(span.service).to eq("buildkite")
78
+ expect(span.type).to eq("custom")
79
+ expect(span.start).to eq(1546002212000000000)
80
+ expect(span.duration).to eq(1_566_000_000_000)
81
+ expect(span.metrics).to eq({_sampling_priority_v1: 2})
82
+ expect(span.meta).to eq({:pipeline=>"bar", :url=>"https://buildkite.com/foo/bar/builds/4472"})
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,15 @@
1
+ require 'json'
2
+
3
+ describe Buildkite::Trace::Client do
4
+
5
+ describe ".submit_trace" do
6
+ context "with valid trace data" do
7
+ it "submits the trace data to the datadog agent"
8
+ it "returns true"
9
+ end
10
+ context "with invalid trace data" do
11
+ it "returns false"
12
+ end
13
+ end
14
+
15
+ end
@@ -0,0 +1,31 @@
1
+ require 'json'
2
+
3
+ describe Buildkite::Trace::Event do
4
+ let(:json) { JSON.dump(data) }
5
+ let(:event) { Buildkite::Trace::Event.build(json)}
6
+
7
+ context "with a build finished event" do
8
+ let(:data) { { "event" => "build.finished"} }
9
+
10
+ it "returns the correct object" do
11
+ expect(event).to be_a(Buildkite::Trace::BuildFinishedEvent)
12
+ end
13
+ end
14
+
15
+ context "with a job finished event" do
16
+ let(:data) { { "event" => "job.finished"} }
17
+
18
+ it "returns the correct object" do
19
+ expect(event).to be_a(Buildkite::Trace::JobFinishedEvent)
20
+ end
21
+ end
22
+
23
+ context "with another event" do
24
+ let(:data) { { "event" => "foo"} }
25
+
26
+ it "returns the correct object" do
27
+ expect(event).to be_a(Buildkite::Trace::UnknownEvent)
28
+ end
29
+ end
30
+
31
+ end
@@ -0,0 +1,109 @@
1
+ require 'json'
2
+
3
+ describe Buildkite::Trace::JobFinishedEvent do
4
+ let(:json_path) { File.join(File.dirname(__FILE__), "..", "..", "fixtures", "buildkite_job_finished.json")}
5
+ let(:json) { JSON.load(File.read(json_path)) }
6
+ let(:event) { Buildkite::Trace::JobFinishedEvent.new(json)}
7
+
8
+ describe '.name' do
9
+ it "returns the correct value" do
10
+ expect(event.name).to eq "job.finished"
11
+ end
12
+ end
13
+
14
+ describe '.job_id' do
15
+ it "returns the job id" do
16
+ expect(event.job_id).to eq "db30e1c2-7200-49db-b3f3-85edcbedec6e"
17
+ end
18
+ end
19
+
20
+ describe '.job_name' do
21
+ it "returns the job name" do
22
+ expect(event.job_name).to eq ":rspec: Run Spec Group 1"
23
+ end
24
+ end
25
+
26
+ describe '.job_slug' do
27
+ it "returns the job slug" do
28
+ expect(event.job_slug).to eq "rspec-run-spec-group-1"
29
+ end
30
+ end
31
+
32
+ describe '.job_state' do
33
+ it "returns the job state" do
34
+ expect(event.job_state).to eq "passed"
35
+ end
36
+ end
37
+
38
+ describe '.job_web_url' do
39
+ it "returns the job URL" do
40
+ expect(event.job_web_url).to eq "https://buildkite.com/foo/bar/builds/4474#db30e1c2-7200-49db-b3f3-85edcbedec6e"
41
+ end
42
+ end
43
+
44
+ describe '.job_started_at' do
45
+ it "returns the correct time" do
46
+ expect(event.job_started_at).to eq Time.utc(2018,12,28,13,23,43)
47
+ end
48
+ end
49
+
50
+ describe '.job_finished_at' do
51
+ it "returns the correct time" do
52
+ expect(event.job_finished_at).to eq Time.utc(2018,12,28,13,26,11)
53
+ end
54
+ end
55
+
56
+ describe '.agent_name' do
57
+ it "returns the agent name" do
58
+ expect(event.agent_name).to eq "build-robot-himem-5cd88946-g74t6-1"
59
+ end
60
+ end
61
+
62
+ describe '.agent_hostname' do
63
+ it "returns the agent hostname" do
64
+ expect(event.agent_hostname).to eq "build-robot-himem-5cd88946-g74t6"
65
+ end
66
+ end
67
+
68
+ describe '.build_id' do
69
+ it "returns the build id" do
70
+ expect(event.build_id).to eq "464b5536-643c-4d70-bdaf-cb50660099f5"
71
+ end
72
+ end
73
+
74
+ describe '.build_branch' do
75
+ it "returns the build branch name" do
76
+ expect(event.build_branch).to eq "master"
77
+ end
78
+ end
79
+
80
+ describe '.pipeline_name' do
81
+ it "returns the pipeline name" do
82
+ expect(event.pipeline_name).to eq "Bar"
83
+ end
84
+ end
85
+
86
+ describe '.pipeline_slug' do
87
+ it "returns the pipeline slug" do
88
+ expect(event.pipeline_slug).to eq "bar"
89
+ end
90
+ end
91
+
92
+ describe '.to_span' do
93
+ let(:span) { event.to_span }
94
+
95
+ it "returns a Span instance with the correct values" do
96
+ expect(span.trace_id).to eq(16600268248679578299)
97
+ expect(span.span_id).to eq(3724764218537855423)
98
+ expect(span.parent_id).to eq(16600268248679578300)
99
+ expect(span.name).to eq("build.job")
100
+ expect(span.resource).to eq(":rspec: Run Spec Group 1")
101
+ expect(span.service).to eq("buildkite")
102
+ expect(span.type).to eq("custom")
103
+ expect(span.start).to eq(1546003423000000000)
104
+ expect(span.duration).to eq(148_000_000_000)
105
+ expect(span.metrics).to eq({_sampling_priority_v1: 2})
106
+ expect(span.meta).to eq({:pipeline=>"bar", :url=>"https://buildkite.com/foo/bar/builds/4474#db30e1c2-7200-49db-b3f3-85edcbedec6e"})
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,9 @@
1
+ require 'json'
2
+
3
+ describe Buildkite::Trace::Span do
4
+
5
+ describe ".to_hash" do
6
+ it "returns a hash with appropriate values"
7
+ end
8
+
9
+ end
@@ -0,0 +1,91 @@
1
+ {
2
+ "event": "build.finished",
3
+ "build": {
4
+ "id": "83636ec4-0643-4d4b-9576-4b4cc9416dbc",
5
+ "url": "https://api.buildkite.com/v2/organizations/foo/pipelines/bar/builds/4472",
6
+ "web_url": "https://buildkite.com/foo/bar/builds/4472",
7
+ "number": 4472,
8
+ "state": "failed",
9
+ "blocked": false,
10
+ "message": "exp: will avoiding JS execution make this more reliable?",
11
+ "commit": "dbf58b93b46ae0ec2b82d85fe98f5925a946837a",
12
+ "branch": "master",
13
+ "tag": null,
14
+ "source": "webhook",
15
+ "creator": {
16
+ "id": "f98b5507-d9ca-4711-b5bb-f2bf145b9d13",
17
+ "name": "James Healy",
18
+ "email": "james@yob.id.au",
19
+ "avatar_url": "https://www.gravatar.com/avatar/febab66d54b972e5f3c04a70a5feb5b5",
20
+ "created_at": "2018-03-27 05:47:37 UTC"
21
+ },
22
+ "created_at": "2018-12-28 13:03:28 UTC",
23
+ "scheduled_at": "2018-12-28 13:03:28 UTC",
24
+ "started_at": "2018-12-28 13:03:32 UTC",
25
+ "finished_at": "2018-12-28 13:29:38 UTC",
26
+ "meta_data": {
27
+ "buildkite:git:commit": "commit dbf58b93b46ae0ec2b82d85fe98f5925a946837a\nAuthor: James Healy <james@yob.id.au>\nAuthorDate: Sat Dec 29 00:02:56 2018 +1100\nCommit: James Healy <james@yob.id.au>\nCommitDate: Sat Dec 29 00:02:56 2018 +1100\n\n exp: will avoiding JS execution make this more reliable?"
28
+ },
29
+ "pull_request": null
30
+ },
31
+ "pipeline": {
32
+ "id": "f7e3be00-737a-4832-8646-11ae7fad909b",
33
+ "url": "https://api.buildkite.com/v2/organizations/foo/pipelines/bar",
34
+ "web_url": "https://buildkite.com/foo/bar",
35
+ "name": "Bar",
36
+ "description": "",
37
+ "slug": "bar",
38
+ "repository": "git@github.com:yob/bar.git",
39
+ "branch_configuration": "",
40
+ "default_branch": "master",
41
+ "skip_queued_branch_builds": true,
42
+ "skip_queued_branch_builds_filter": "",
43
+ "cancel_running_branch_builds": false,
44
+ "cancel_running_branch_builds_filter": "",
45
+ "provider": {
46
+ "id": "github",
47
+ "settings": {
48
+ "trigger_mode": "code",
49
+ "build_pull_requests": true,
50
+ "pull_request_branch_filter_enabled": false,
51
+ "skip_pull_request_builds_for_existing_commits": true,
52
+ "build_pull_request_forks": false,
53
+ "prefix_pull_request_fork_branch_names": false,
54
+ "build_tags": false,
55
+ "publish_commit_status": true,
56
+ "publish_commit_status_per_step": false,
57
+ "separate_pull_request_statuses": false,
58
+ "publish_blocked_as_pending": false,
59
+ "repository": "yob/bar",
60
+ "pull_request_branch_filter_configuration": ""
61
+ },
62
+ "webhook_url": "https://webhook.buildkite.com/deliver/849a6755fd449c310b936150fd3585e42070c1712b7c52f757"
63
+ },
64
+ "builds_url": "https://api.buildkite.com/v2/organizations/foo/pipelines/bar/builds",
65
+ "badge_url": "https://badge.buildkite.com/12de09c168b7ad23e83e96c62be7698f3d1102faea93b60803.svg",
66
+ "created_at": "2016-05-25 04:34:52 UTC",
67
+ "scheduled_builds_count": 0,
68
+ "running_builds_count": 1,
69
+ "scheduled_jobs_count": 4,
70
+ "running_jobs_count": 6,
71
+ "waiting_jobs_count": 0,
72
+ "steps": [
73
+ {
74
+ "type": "script",
75
+ "name": ":pipeline:",
76
+ "command": ".buildkite/upload-pipeline",
77
+ "artifact_paths": "",
78
+ "branch_configuration": "",
79
+ "env": {},
80
+ "timeout_in_minutes": null,
81
+ "agent_query_rules": [],
82
+ "concurrency": null,
83
+ "parallelism": null
84
+ }
85
+ ]
86
+ },
87
+ "sender": {
88
+ "id": "f98b5507-d9ca-4711-b5bb-f2bf145b9d13",
89
+ "name": "James Healy"
90
+ }
91
+ }
@@ -0,0 +1,141 @@
1
+ {
2
+ "event": "job.finished",
3
+ "job": {
4
+ "id": "db30e1c2-7200-49db-b3f3-85edcbedec6e",
5
+ "type": "script",
6
+ "name": ":rspec: Run Spec Group 1",
7
+ "agent_query_rules": [
8
+ "queue=default"
9
+ ],
10
+ "state": "passed",
11
+ "build_url": "https://api.buildkite.com/v2/organizations/foo/pipelines/bar/builds/4474",
12
+ "web_url": "https://buildkite.com/foo/bar/builds/4474#db30e1c2-7200-49db-b3f3-85edcbedec6e",
13
+ "log_url": "https://api.buildkite.com/v2/organizations/foo/pipelines/bar/builds/4474/jobs/db30e1c2-7200-49db-b3f3-85edcbedec6e/log",
14
+ "raw_log_url": "https://api.buildkite.com/v2/organizations/foo/pipelines/bar/builds/4474/jobs/db30e1c2-7200-49db-b3f3-85edcbedec6e/log.txt",
15
+ "artifacts_url": "https://api.buildkite.com/v2/organizations/foo/pipelines/bar/builds/4474/jobs/db30e1c2-7200-49db-b3f3-85edcbedec6e/artifacts",
16
+ "command": "./auto/run-tests",
17
+ "exit_status": 0,
18
+ "artifact_paths": "reports/*;",
19
+ "agent": {
20
+ "id": "673cacbc-1920-4b4b-8673-a9a0beb87822",
21
+ "url": "https://api.buildkite.com/v2/organizations/foo/agents/673cacbc-1920-4b4b-8673-a9a0beb87822",
22
+ "web_url": "https://buildkite.com/organizations/foo/agents/673cacbc-1920-4b4b-8673-a9a0beb87822",
23
+ "name": "build-robot-himem-5cd88946-g74t6-1",
24
+ "connection_state": "connected",
25
+ "ip_address": "35.189.61.14",
26
+ "hostname": "build-robot-himem-5cd88946-g74t6",
27
+ "user_agent": "buildkite-agent/3.6.0.2618 (linux; amd64)",
28
+ "version": "3.6.0",
29
+ "creator": null,
30
+ "created_at": "2018-12-28 12:19:02 UTC",
31
+ "job": null,
32
+ "last_job_finished_at": "2018-12-28 13:26:11 UTC",
33
+ "priority": 0,
34
+ "meta_data": [
35
+ "queue=default",
36
+ "himem=true"
37
+ ]
38
+ },
39
+ "created_at": "2018-12-28 13:21:40 UTC",
40
+ "scheduled_at": "2018-12-28 13:17:08 UTC",
41
+ "started_at": "2018-12-28 13:23:43 UTC",
42
+ "finished_at": "2018-12-28 13:26:11 UTC",
43
+ "runnable_at": "2018-12-28 13:21:40 UTC",
44
+ "retried": false,
45
+ "retried_in_job_id": null,
46
+ "retries_count": null,
47
+ "parallel_group_index": 1,
48
+ "parallel_group_total": 5
49
+ },
50
+ "build": {
51
+ "id": "464b5536-643c-4d70-bdaf-cb50660099f5",
52
+ "url": "https://api.buildkite.com/v2/organizations/foo/pipelines/bar/builds/4474",
53
+ "web_url": "https://buildkite.com/foo/bar/builds/4474",
54
+ "number": 4474,
55
+ "state": "running",
56
+ "blocked": false,
57
+ "message": "exp: will avoiding JS execution make this more reliable?",
58
+ "commit": "f9df15515206cf6d0ae552391b364fb3414c7958",
59
+ "branch": "master",
60
+ "tag": null,
61
+ "source": "webhook",
62
+ "creator": {
63
+ "id": "f98b5507-d9ca-4711-b5bb-f2bf145b9d13",
64
+ "name": "James Healy",
65
+ "email": "james@yob.id.au",
66
+ "avatar_url": "https://www.gravatar.com/avatar/febab66d54b972e5f3c04a70a5feb5b5",
67
+ "created_at": "2018-03-27 05:47:37 UTC"
68
+ },
69
+ "created_at": "2018-12-28 13:17:08 UTC",
70
+ "scheduled_at": "2018-12-28 13:17:07 UTC",
71
+ "started_at": "2018-12-28 13:21:31 UTC",
72
+ "finished_at": null,
73
+ "meta_data": {
74
+ "buildkite:git:commit": "commit f9df15515206cf6d0ae552391b364fb3414c7958\nAuthor: James Healy <james@yob.id.au>\nAuthorDate: Sat Dec 29 00:02:56 2018 +1100\nCommit: James Healy <james@yob.id.au>\nCommitDate: Sat Dec 29 00:16:47 2018 +1100\n\n exp: will avoiding JS execution make this more reliable?"
75
+ },
76
+ "pull_request": null
77
+ },
78
+ "pipeline": {
79
+ "id": "f7e3be00-737a-4832-8646-11ae7fad909b",
80
+ "url": "https://api.buildkite.com/v2/organizations/foo/pipelines/bar",
81
+ "web_url": "https://buildkite.com/foo/bar",
82
+ "name": "Bar",
83
+ "description": "",
84
+ "slug": "bar",
85
+ "repository": "git@github.com:yob/bar.git",
86
+ "branch_configuration": "",
87
+ "default_branch": "master",
88
+ "skip_queued_branch_builds": true,
89
+ "skip_queued_branch_builds_filter": "",
90
+ "cancel_running_branch_builds": false,
91
+ "cancel_running_branch_builds_filter": "",
92
+ "provider": {
93
+ "id": "github",
94
+ "settings": {
95
+ "trigger_mode": "code",
96
+ "build_pull_requests": true,
97
+ "pull_request_branch_filter_enabled": false,
98
+ "skip_pull_request_builds_for_existing_commits": true,
99
+ "build_pull_request_forks": false,
100
+ "prefix_pull_request_fork_branch_names": false,
101
+ "build_tags": false,
102
+ "publish_commit_status": true,
103
+ "publish_commit_status_per_step": false,
104
+ "separate_pull_request_statuses": false,
105
+ "publish_blocked_as_pending": false,
106
+ "repository": "yob/bar",
107
+ "pull_request_branch_filter_configuration": ""
108
+ },
109
+ "webhook_url": "https://webhook.buildkite.com/deliver/849a6755fd449c310b936150fd3585e42070c1712b7c52f757"
110
+ },
111
+ "builds_url": "https://api.buildkite.com/v2/organizations/foo/pipelines/bar/builds",
112
+ "badge_url": "https://badge.buildkite.com/12de09c168b7ad23e83e96c62be7698f3d1102faea93b60803.svg",
113
+ "created_at": "2016-05-25 04:34:52 UTC",
114
+ "env": {
115
+ "GITHUB_SSH_KEY": "/root/.ssh/id_rsa"
116
+ },
117
+ "scheduled_builds_count": 0,
118
+ "running_builds_count": 2,
119
+ "scheduled_jobs_count": 11,
120
+ "running_jobs_count": 6,
121
+ "waiting_jobs_count": 0,
122
+ "steps": [
123
+ {
124
+ "type": "script",
125
+ "name": ":pipeline:",
126
+ "command": ".buildkite/upload-pipeline",
127
+ "artifact_paths": "",
128
+ "branch_configuration": "",
129
+ "env": {},
130
+ "timeout_in_minutes": null,
131
+ "agent_query_rules": [],
132
+ "concurrency": null,
133
+ "parallelism": null
134
+ }
135
+ ]
136
+ },
137
+ "sender": {
138
+ "id": "f98b5507-d9ca-4711-b5bb-f2bf145b9d13",
139
+ "name": "James Healy"
140
+ }
141
+ }
@@ -0,0 +1 @@
1
+ require "buildkite-trace"
metadata ADDED
@@ -0,0 +1,135 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: buildkite-trace
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - James Healy
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-07-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: shotgun
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: puma
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: digest-crc
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: sinatra
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: A mini rack app that converts buildkite webhooks into datadog APM traces
84
+ email:
85
+ - james@yob.id.au
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files:
89
+ - README.md
90
+ - MIT-LICENSE
91
+ files:
92
+ - MIT-LICENSE
93
+ - README.md
94
+ - images/build-chart.png
95
+ - images/build-waterfall.png
96
+ - lib/buildkite-trace.rb
97
+ - lib/buildkite/trace/app.rb
98
+ - lib/buildkite/trace/build_finished_event.rb
99
+ - lib/buildkite/trace/client.rb
100
+ - lib/buildkite/trace/event.rb
101
+ - lib/buildkite/trace/job_finished_event.rb
102
+ - lib/buildkite/trace/span.rb
103
+ - lib/buildkite/trace/unknown_event.rb
104
+ - spec/buildkite/trace/build_finished_event_spec.rb
105
+ - spec/buildkite/trace/client_spec.rb
106
+ - spec/buildkite/trace/event_spec.rb
107
+ - spec/buildkite/trace/job_finished_event_spec.rb
108
+ - spec/buildkite/trace/span_spec.rb
109
+ - spec/fixtures/buildkite_build_finished.json
110
+ - spec/fixtures/buildkite_job_finished.json
111
+ - spec/spec_helper.rb
112
+ homepage: http://github.com/yob/buildkite-trace
113
+ licenses:
114
+ - MIT
115
+ metadata: {}
116
+ post_install_message:
117
+ rdoc_options: []
118
+ require_paths:
119
+ - lib
120
+ required_ruby_version: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: 1.9.3
125
+ required_rubygems_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ requirements: []
131
+ rubygems_version: 3.0.1
132
+ signing_key:
133
+ specification_version: 4
134
+ summary: A mini rack app that converts buildkite webhooks into datadog APM traces
135
+ test_files: []