Skip to content

[receiver/faroreceiver] Add Faro receiver logic to wireframe#39588

Merged
atoulme merged 18 commits into
open-telemetry:mainfrom
t00mas:faro-receiver
May 8, 2025
Merged

[receiver/faroreceiver] Add Faro receiver logic to wireframe#39588
atoulme merged 18 commits into
open-telemetry:mainfrom
t00mas:faro-receiver

Conversation

@t00mas

@t00mas t00mas commented Apr 23, 2025

Copy link
Copy Markdown
Contributor

Description

Faro receiver package enables Faro-compatible endpoints. This makes it work.

Link to tracking issue

Fixes #19180

Testing

Adding more unit tests.

@t00mas t00mas requested review from a team and dehaansa as code owners April 23, 2025 14:56
@github-actions github-actions Bot added receiver/faro cmd/otelcontribcol otelcontribcol command labels Apr 23, 2025
@github-actions github-actions Bot requested review from mar4uk and rlankfo April 23, 2025 14:57
@t00mas

t00mas commented Apr 23, 2025

Copy link
Copy Markdown
Contributor Author

Note: I'm basically copying #38224 from @dark0dave and making updates

@atoulme atoulme marked this pull request as draft April 24, 2025 06:01
@atoulme

atoulme commented Apr 24, 2025

Copy link
Copy Markdown
Contributor

Moving to draft while this PR is being worked on. Please mark ready to review and ping @dehaansa when done.

@t00mas t00mas marked this pull request as ready for review April 24, 2025 15:01
Comment thread receiver/faroreceiver/utils.go Outdated
@t00mas t00mas force-pushed the faro-receiver branch 2 times, most recently from 9457ef0 to 7fd4f88 Compare April 25, 2025 15:23
@atoulme

atoulme commented Apr 29, 2025

Copy link
Copy Markdown
Contributor

@dehaansa please review

Comment on lines +57 to +69
var err error
receiver := receivers.GetOrAdd(
fCfg,
func() component.Component {
var rcv component.Component
rcv, err = newFaroReceiver(fCfg, &set)
return rcv
},
)
if err != nil {
return nil, err
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be refactored into a function.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactoring 👍🏼

Comment thread receiver/faroreceiver/receiver.go Outdated
}

func (r *faroReceiver) handleFaroRequest(resp http.ResponseWriter, req *http.Request) {
resp.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should these only be set in the preflight request response path?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Harmless, but moving these to the preflight path below it 👍🏼

Comment thread receiver/faroreceiver/receiver.go Outdated
Comment on lines +171 to +177
if err == nil {
err = r.nextTraces.ConsumeTraces(req.Context(), traces)
if err != nil {
errors = append(errors, fmt.Sprintf("failed to push traces: %v", err))
}
} else {
r.settings.Logger.Debug("Faro traces are nil, skipping")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused here - if err != nil we log that "traces are nil", but we haven't actually checked that. Additionally, while the current implementation of the translator might always return a nil err we shouldn't assume that given that err is part of the function definition, we should handle this like a normal function that can return an err.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I messed up with a linter error here and removed the check for traces (and logs) - I'm putting it back now

Comment thread receiver/faroreceiver/receiver.go Outdated
Comment on lines +185 to +201
if err == nil {
err = r.nextLogs.ConsumeLogs(req.Context(), logs)
if err != nil {
errors = append(errors, fmt.Sprintf("failed to push logs: %v", err))
}
} else {
r.settings.Logger.Debug("Faro logs are nil, skipping")
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same fix

Comment thread receiver/faroreceiver/receiver.go Outdated
r.settings.Logger.Debug("Faro traces are nil, skipping")
}
} else {
r.settings.Logger.Debug("Traces consumer not registered, skipping")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be a noisy debug log, and I'm not sure it provides value.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing

Comment thread receiver/faroreceiver/receiver.go Outdated
if err == nil {
err = r.nextTraces.ConsumeTraces(req.Context(), traces)
if err != nil {
errors = append(errors, fmt.Sprintf("failed to push traces: %v", err))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit : "push" sounds like an exporter action

Suggested change
errors = append(errors, fmt.Sprintf("failed to push traces: %v", err))
errors = append(errors, fmt.Sprintf("failed to pass traces to next consumer: %v", err))

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applying suggestion (sorry for not accepting this one straight away, modified this along the other changes from above)

Comment thread receiver/faroreceiver/receiver.go Outdated
if err == nil {
err = r.nextLogs.ConsumeLogs(req.Context(), logs)
if err != nil {
errors = append(errors, fmt.Sprintf("failed to push logs: %v", err))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit : "push" sounds like an exporter action

Suggested change
errors = append(errors, fmt.Sprintf("failed to push logs: %v", err))
errors = append(errors, fmt.Sprintf("failed to pass logs to next consumer: %v", err))

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same

Comment thread receiver/faroreceiver/receiver.go Outdated
}

if len(errors) > 0 {
r.settings.Logger.Error("Failed to process Faro payload", zap.Any("payload", payload), zap.Any("errors", errors))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that clients may re-send, should we fail fast? IE if traces fails, do we want to try to send logs?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think yes - I'm making this fail fast so not to waste time when things go wrong.

farotranslator "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/faro"
)

const faroPath = "/"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if I understand the faro spec correctly, should this support receiving data on /collect/{appKey}?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the spec needs to be updated, I was assuming anyone was free to receive data on any URL they wish to - @mar4uk ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree, let's change the spec. It should be possible to use any URL

resp.WriteHeader(http.StatusOK)
}

func (r *faroReceiver) errorHandler(w http.ResponseWriter, _ *http.Request, errMsg string, statusCode int) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the spec, shouldn't this be json encoded?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep! Modifying that
I'm not sure about the schema being right in the spec though - @mar4uk I think the spec mixes Faro payload Exceptions with what the receiver can return

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, right, the schema is not correct. It indeed mixes Faro payload Exceptions with error that actually returned

@atoulme atoulme marked this pull request as draft May 2, 2025 06:16
@atoulme

atoulme commented May 2, 2025

Copy link
Copy Markdown
Contributor

Moving to draft, please fix conflicts and address review and mark ready for review again.

@t00mas t00mas force-pushed the faro-receiver branch 2 times, most recently from c48b82a to 666bb10 Compare May 2, 2025 13:53
@t00mas t00mas marked this pull request as ready for review May 2, 2025 14:36
@t00mas t00mas force-pushed the faro-receiver branch 4 times, most recently from adbdda5 to f3938a2 Compare May 6, 2025 14:58

@dehaansa dehaansa left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New concern out of the refactoring.

}

if err := json.NewEncoder(w).Encode(resp); err != nil {
r.settings.Logger.Error("Could not write JSON response",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it fails to write should we default to a precalculated "json" string? Otherwise this seems like it's not responding at all.

@t00mas t00mas May 6, 2025

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't it overkill? json.NewEncoder(w).Encode() only fails (I think) if writing to a closed connection, mem corruption, system-level I/O errors...

A fallback like

fallback := fmt.Sprintf(`{"error":%q,"code":%d,"message":%q}`, http.StatusText(statusCode), statusCode, errMsg)

is easy to add now, but I don't see much benefit.

@dehaansa dehaansa May 7, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hear that, it feels strange handling an error case and not explicitly managing that error. A comment in the code to that effect would be nice for now, in case this ends up being an unexpected issue in the future.

@dehaansa dehaansa left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@dehaansa dehaansa added the ready to merge Code review completed; ready to merge by maintainers label May 7, 2025
@atoulme atoulme merged commit a7884df into open-telemetry:main May 8, 2025
182 checks passed
@github-actions github-actions Bot added this to the next release milestone May 8, 2025
@mar4uk mar4uk mentioned this pull request May 15, 2025
dragonlord93 pushed a commit to dragonlord93/opentelemetry-collector-contrib that referenced this pull request May 23, 2025
…lemetry#39588)

<!--Ex. Fixing a bug - Describe the bug and how this fixes the issue.
Ex. Adding a feature - Explain what this achieves.-->
#### Description
Faro receiver package enables Faro-compatible endpoints. This makes it
work.

<!-- Issue number (e.g. open-telemetry#1234) or full URL to issue, if applicable. -->
#### Link to tracking issue
Fixes
open-telemetry#19180

<!--Describe what testing was performed and which tests were added.-->
#### Testing
Adding more unit tests.
dd-jasminesun pushed a commit to DataDog/opentelemetry-collector-contrib that referenced this pull request Jun 23, 2025
…lemetry#39588)

<!--Ex. Fixing a bug - Describe the bug and how this fixes the issue.
Ex. Adding a feature - Explain what this achieves.-->
#### Description
Faro receiver package enables Faro-compatible endpoints. This makes it
work.

<!-- Issue number (e.g. #1234) or full URL to issue, if applicable. -->
#### Link to tracking issue
Fixes
open-telemetry#19180

<!--Describe what testing was performed and which tests were added.-->
#### Testing
Adding more unit tests.
receivers:
faro:
endpoint: 'localhost:8081'
cors:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is incorrect. his should be something like:

receivers:
  faro:
    protocols:
      http:
        endpoint: 'localhost:8081'
        cors:
          ..

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I'm not even sure the cors implementation works at all. Both the config I've posted above and the example in the readme do not change the cors response headers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cmd/otelcontribcol otelcontribcol command ready to merge Code review completed; ready to merge by maintainers receiver/faro

Projects

None yet

Development

Successfully merging this pull request may close these issues.

New component: Faro Receiver

7 participants