-
Notifications
You must be signed in to change notification settings - Fork 212
feat: add net_ldap instrumentation #1587
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: add net_ldap instrumentation #1587
Conversation
instrumentation/net_ldap/lib/opentelemetry/instrumentation/net/ldap/instrumentation.rb
Show resolved
Hide resolved
yield(payload).tap do |response| | ||
annotate_span_with_response!(span, response) | ||
end | ||
rescue StandardError => e |
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.
Doesn't in_span
already handle Error Recording and setting the status?
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.
Yes it does, but it doesn't add the ldap.error_message
attribute. I've updated this a bit, and in 0583992 we'll rescue specifically on a ::Net::LDAP::Error
LDAP::Instrumentation.instance.config | ||
end | ||
|
||
def annotate_span_with_response!(span, response) |
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.
Only add a !
if you have an existing method that does not have a !
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.
|
||
return if ::Net::LDAP::ResultCodesNonError.include?(status_code) | ||
|
||
span.record_exception(error_message) unless error_message.empty? |
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 believe record_exception is an explicit helper for exception events. Consider using the Span Status Code description instead.
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.
release-please-config.json
Outdated
} | ||
} | ||
} | ||
} |
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.
} | |
} | |
OpenTelemetry::SemanticConventions::Trace::NET_PEER_NAME => host || hosts, | ||
OpenTelemetry::SemanticConventions::Trace::NET_PEER_PORT => port, | ||
OpenTelemetry::SemanticConventions::Trace::PEER_SERVICE => instrumentation_config[:peer_service] | ||
}.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes) |
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.
why is this amending HTTP Client attributes? How is that relevant to LDAP lookups?
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.
TBH I just took the already existing stale PR that originally was opened to add this instrumentation. That did the job for me, and I thought it might be beneficial for others to have this instrumentation more easily available.
I rushed this a bit and skipped the due diligence (sorry!), so I'm glad you ask.
It doesn't: I removed it.
@encryption = args[:encryption] | ||
end | ||
|
||
def instrument(event, payload) |
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.
Do we want more specific attribute mappers here for each of these events?
https://github.com/search?q=repo%3Aruby-ldap%2Fruby-net-ldap+%2Finstrument+%22%2F&type=code
I do not particularly like the practice of dumping json strings where we do not know if the contents of the provided payload have sensitive information in them.
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 agree.
My naive thought was that it would be handled in net-ldap
itself, but upon closer inspection I see that this instrumentation can leak e.g. passwords in cleartext.
I'll need some time to figure out which specific attributes to include.
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.
Fixed and added test in 3d2ff26
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 think a good starting point would be to capture the name of the operation being performed ie open, read, parse_pdu.
|
||
tracer.in_span( | ||
event, | ||
attributes: attributes.compact, |
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.
This allocates and extra hash object.
lets avoid that by checking if the values are present before adding them to the hash.
tracer.in_span( | ||
event, | ||
attributes: attributes.compact, | ||
kind: :client |
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.
Do you think LDAP qualifies as RPC? Would using RPC client semantics be right for this?
Would using ECS style events make more sense for these?
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 was inclined to say LDAP qualifies as RPC, but my AI friend does not agree with me. Apparently LDAP itself is not RPC, but it is often combined with RPC (e.g. when joining computers to Windows domains), but we're only instrumenting LDAP in this case. Semconv doesn't specify anything for ldap
, and other languages don't seem to have ldap instrumentation.
I'm not sure what to do here.
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.
Good points. I was also wondering about SemConv as I'm reading through this. I asked the #opentelemetry-semantic-conventions channel on CNCF Slack for advice.
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.
def initialize(args = {}) | ||
super | ||
|
||
@instrumentation_service = args[:instrumentation_service] || OpenTelemetry::Instrumentation::Net::LDAP::InstrumentationService.new({ |
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.
Another thought I have here, what if we added this otel instrumentation as a decorator to the injected service?
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.
Hi @scbjans, thanks for opening this PR.
I'm not very familiar with LDAP, so I'll take another pass once I learn a bit more. For now, I left a few comments.
In addition to those comments, would you mind updating the CODEOWNERS file to list you as the owner of this gem? PR assignment for CODEOWNERS is currently broken, but I'm hoping to get it fixed soon.
gem 'opentelemetry-api' | ||
gem 'opentelemetry-common' | ||
gem 'opentelemetry-instrumentation-base' |
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 be able to leave these out, since they're dependencies of the other gems.
gem 'opentelemetry-api' | |
gem 'opentelemetry-common' | |
gem 'opentelemetry-instrumentation-base' |
tracer.in_span( | ||
event, | ||
attributes: attributes.compact, | ||
kind: :client |
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.
Good points. I was also wondering about SemConv as I'm reading through this. I asked the #opentelemetry-semantic-conventions channel on CNCF Slack for advice.
instrumentation/net_ldap/lib/opentelemetry/instrumentation/net/ldap/instrumentation_service.rb
Outdated
Show resolved
Hide resolved
instrumentation/net_ldap/lib/opentelemetry/instrumentation/net/ldap/instrumentation_service.rb
Outdated
Show resolved
Hide resolved
instrumentation/net_ldap/lib/opentelemetry/instrumentation/net/ldap/instrumentation_service.rb
Outdated
Show resolved
Hide resolved
instrumentation/net_ldap/lib/opentelemetry/instrumentation/net/ldap/instrumentation_service.rb
Outdated
Show resolved
Hide resolved
|
||
def instrument(event, payload) | ||
attributes = { | ||
'ldap.auth' => auth.except(:password).to_json, |
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.
Do we need auth given we removed it from db etc?
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'm not sure why it was removed from db, but I think it's valuable to see which user connects to ldap; e.g. to troubleshoot permissions
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 believe it was in relation to the range of different auth methods/mechanism that could be used ie certificates vs user credentials.
The name Auth doesn't feel scoped enough as it could mean many things. In ldap v3 SASL is supported which opens up additional techniques.
instrumentation/net_ldap/lib/opentelemetry/instrumentation/net/ldap/instrumentation_service.rb
Outdated
Show resolved
Hide resolved
instrumentation/net_ldap/lib/opentelemetry/instrumentation/net/ldap/instrumentation_service.rb
Outdated
Show resolved
Hide resolved
instrumentation/net_ldap/lib/opentelemetry/instrumentation/net/ldap/instrumentation_service.rb
Show resolved
Hide resolved
@kaylareopelle thanks for your feedback; I updated it in 7264acb @thompson-tomo thank you as well for your feedback, I believe I addressed it in 44a1d54 |
instrumentation/net_ldap/lib/opentelemetry/instrumentation/net/ldap/instrumentation_service.rb
Show resolved
Hide resolved
def instrument(event, payload) | ||
attributes = { | ||
'ldap.auth' => auth.except(:password).to_json, | ||
'ldap.base' => base, |
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 this become ldap.tree.base
or similar that way we have potential of adding other properties for the tree.
attributes = { | ||
'ldap.auth' => auth.except(:password).to_json, | ||
'ldap.base' => base, | ||
'ldap.encryption' => encryption.to_json, |
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.
Not sure of the benefits of this given it could be a hash of properties.
Largely based on prior work in #1432 by @Hareramrai and @jdehaan
Since that PR seems stale, I've updated it with some small edits to comply with release management using toys.
Should fix: github.com//issues/669