-
Notifications
You must be signed in to change notification settings - Fork 31
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A little less than halfway but leaving some nitpick comments already.
agent/agent.go
Outdated
@@ -60,41 +60,62 @@ type Agent struct { | |||
// NewAgent returns a new Agent object, ready to be started | |||
func NewAgent(conf *config.AgentConfig, exit chan struct{}) *Agent { | |||
dynConf := config.NewDynamicConfig() | |||
|
|||
// inter-component channels | |||
rawTraceChan := make(chan model.Trace, 5000) // about 1000 traces/sec for 5 sec |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we take this opportunity to remove some copies here too (chan *model.Trace)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
model.Trace
being a slice it isn't such a big deal.
https://github.com/golang/go/wiki/CodeReviewComments#receiver-type
But it falls under the:
If the receiver is a struct, array or slice and any of its elements is a pointer to something that might be mutating, prefer a pointer receiver, as it will make the intention more clear to the reader.
So it is mostly to make the code more explicit ; I'll leave it as a comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True about it just being a slice. Hadn't noticed. Comment was mostly because sampledTraceChan indeed uses *model.Trace
and it felt a bit weird to have both styles.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Totally ; I'm not sure yet about what is the best there / I'd rather take enough time to make the right decision. Left it as a comment, it can be a later task to review these questions across the entire Agent.
agent/concentrator.go
Outdated
} | ||
sort.Strings(c.aggregators) | ||
return &c | ||
} | ||
|
||
// Start starts the writer. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
starts the concentrator
@@ -148,7 +148,7 @@ func runAgent(exit chan struct{}) { | |||
|
|||
if opts.info { | |||
if err := info.Info(os.Stdout, agentConf); err != nil { | |||
// need not display the error, Info should do it already | |||
os.Stdout.WriteString(fmt.Sprintf("failed to print info: %s\n", err)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Less "should" more action 👍 😄
agent/receiver.go
Outdated
@@ -71,8 +71,6 @@ type HTTPReceiver struct { | |||
func NewHTTPReceiver(conf *config.AgentConfig, dynConf *config.DynamicConfig) *HTTPReceiver { | |||
// use buffered channels so that handlers are not waiting on downstream processing | |||
return &HTTPReceiver{ | |||
traces: make(chan model.Trace, 5000), // about 1000 traces/sec for 5 sec |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should be passing these by argument. Technically this is a constructor function so whatever comes out should be working without needing to modify unexported fields (IMO)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very good point! It both makes the code more explicit and avoid sneaky bugs. Updated.
agent/sampler.go
Outdated
// NewScoreEngine creates a new empty sampler ready to be started | ||
func NewScoreEngine(conf *config.AgentConfig) *Sampler { | ||
// NewScoreSampler creates a new empty sampler ready to be started | ||
func NewScoreSampler(conf *config.AgentConfig) *Sampler { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, it kinda feels cleaner to me if we would pass sampled
as an argument to the constructors.
agent/sampler.go
Outdated
// NewPriorityEngine creates a new empty distributed sampler ready to be started | ||
func NewPriorityEngine(conf *config.AgentConfig, dynConf *config.DynamicConfig) *Sampler { | ||
// NewPrioritySampler creates a new empty distributed sampler ready to be started | ||
func NewPrioritySampler(conf *config.AgentConfig, dynConf *config.DynamicConfig) *Sampler { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto
agent/sampler.go
Outdated
switch s.engine.(type) { | ||
case *sampler.ScoreEngine: | ||
info.UpdateSamplerInfo(info.SamplerInfo{EngineType: engineType, Stats: stats, State: state}) | ||
case *sampler.PriorityEngine: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be cleaner as methods of engine. Let method resolution do its work.
model/stats_payload.go
Outdated
|
||
// StatsPayload represents the payload to be flushed to the stats endpoint | ||
type StatsPayload struct { | ||
HostName string `json:"hostnamed"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo hostname
?
writer/datadog_endpoint.go
Outdated
return err | ||
} | ||
|
||
// Set API key in the header and issue the request |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i realize this is copy-paste, but the comment disagrees with the code. We still send the api key as a query param rather than through headers.
Since the code is being touched maybe leave a TODO to really move it to HTTP headers. The new backend endpoints should support this as the main way to auth.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, I moved it to HTTP headers (the same as https://github.com/DataDog/datadog-agent/blob/master/pkg/forwarder/forwarder.go#L66 )
e5bbbf1
to
2575975
Compare
Since the code is now more readable, we can also remove examples from doc strings and only rely on tests or the more readable template.
5ae1eb1
to
1e367ac
Compare
agent/receiver_test.go
Outdated
|
||
receiver.traces = rawTraceChan | ||
receiver.services = serviceChan |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Redundant with arguments being passed to constructor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Went through it all. Besides the nitpick, only other observation is that we seem to have a lot of duplication around the writers (the whole start/stop/run, switch waiting for data, flushing, etc.). Perhaps having a BaseWriter composed into all of the writers and have the BaseWriter encode that common logic could work? Anyway, I can also explore this as part of the logic for the async retry stuff :)
LGTM
model/trace.proto
Outdated
uint64 traceID = 1; | ||
repeated Span spans = 2; | ||
int64 startTime = 6; | ||
int64 endTime = 7; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: extra space
Yes that's the goal: I tried to keep writers as independent/uncoupled as possible ; that way it won't constraint us when we will have more writer-specific code (different buffering, retrying, logging, metrics, ...). After that we will be able to see what's in common and share it! (even if, sometimes, we can't avoid some dupe in Go). |
57570be
to
33b1bab
Compare
45ed17a
to
33b1bab
Compare
} | ||
|
||
headers := map[string]string{ | ||
languageHeaderKey: strings.Join(info.Languages(), "|"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently updating our backend, as this header will be enough on the stats payload, not needed for service and traces.
Split the Writer into 3 different writers, writing to 3 new endpoints:
/traces
,TraceWriter
: new protobuf endpoint. Only contains traces (and soon transactions)./stats
,StatsWriter
: similar to the previous AgentPayload but without the traces./services
,ServiceWriter
: similar to before. But now a writer on its own.They are split as they differ in terms of encoding, compression, replay logic, ...
To make that work properly, there is some heavy rewiring.
agent/agent.go
. Traces and services are sent to their writer as soon as processed. The concentrator generates and flush StatsBuckets itself to the writer. Then writer are free to send it over the wire when/how they want (allowing future different flush conditions / replay features).Endpoint
API to be much simpler, simply writing bytes with HTTP headers. Also extract the client/proxy configuration.TracePayload
is our first protobuf payload. For now it isn't compressed, we should benchmarks options before picking a compression.info
to make it work with the new metrics / writers.TODOs before being able to merge it: