-
Notifications
You must be signed in to change notification settings - Fork 141
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
HTTP dependency request tracking #129
Conversation
Add automatic collection of dependency HTTP request data.
} | ||
|
||
public trackRequest(request: http.ServerRequest, response: http.ServerResponse, properties?: { [key: string]: string; }) { | ||
RequestTracking.trackRequest(this, request, response, properties); | ||
public trackServerRequest(request: http.ServerRequest, response: http.ServerResponse, properties?: { [key: string]: string; }) { |
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.
Is this a breaking change? Would it be better to continue calling this trackRequest and merging the new trackClientRequest with trackDependency for compatibility with previous versions and consistency with AI terms for what these are?
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's a breaking change. I suppose renaming this method is not that important.
However merging trackClientRequest
with trackDependency
doesn't make sense to me: the parameters are completely different, even though they end up doing something similar.
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 support both methods trackRequest
and trackDependency
. See API Summary
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, but what about the trackClientRequest
method I have added here? Without that, it would be difficult for an application to manually track HTTP dependency requests, because it takes a few dozen non-obvious lines of code to convert a http.ClientRequest
into appropriate parameters for trackDependency
. (Perhaps it could be renamed trackDependencyRequest
instead of trackClientRequest
.)
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.
trackDependencyRequest
sounds good.
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 corrected the naming of Client
methods. Now there is:
trackRequest
- unchangedtrackDependency
- added optionaltarget
parameter at the endtrackDependencyRequest
- new, alternative totrackDependency
that is appropriate to use if you have ahttp.ClientRequest
object that you want to track manually (when autocollection is disabled).
Thanks for sending a pull request! This is a really good addition to the Node.js SDK. I agree with @OsvaldoRosado, we should keep the naming consistent with other AppInsights SDKs. This is "Request" (for all requests that node.js is receiving) and "Dependency" (for all requests the node.js is sending). |
} | ||
|
||
public trackDependency( | ||
name: string, | ||
commandName: string, | ||
target: string, |
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.
The addition of the target
parameter here is a breaking change. To avoid that it will need to be moved to an optional parameter at the end, although I think the intention of the new contract is actually that it should be required.
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 don't think our bond currently asks for this field to be required. It might not be so bad to move this to the end and mark optional. Anyone have strong thoughts on that?
EDIT: Is it possible to fill this by default if its left unfilled? Our bond marks commandName as deprecated in favor of data. If this is filled like data it would include "http urls with all query parameters"
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 don't see what "data" field you are referring to. RemoteDependencyData
doesn't have a "data" field.
The target
could be auto-filled by parsing the hostname out of the supplied commandName
argument if it is a valid URI, or the name
argument if it is a HTTP method + URI.
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.
Sorry, the data field is one we're not using in this SDK yet, but is what commandName is migrating to eventually, as we deprecated it in the schema. I was just noting, as you did, that we can get the hostname out of commandName, based off of what the schema said the field should contain.
With this in mind, we should move target to the end and mark optional. Like @KamilSzostak mentions below, this avoids breaking existing users.
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.
OK, I moved target
to the end. If not supplied it will attempt to auto-fill by parsing the commandName
.
I agree, this is awesome 👍 |
let urlObject = url.parse(this.url); | ||
urlObject.search = undefined; | ||
urlObject.hash = undefined; | ||
let dependencyName = this.method + " " + url.format(urlObject); |
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.
Could you make sure that this.method
is upper-cased? It should be consistent with the JavaScript SDK - see
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.
const request: http.ClientRequest = originalRequest.call( | ||
originalRequest, options, ...requestArgs); | ||
if (request) { | ||
AutoCollectClientRequests.trackRequest(this._client, options, 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.
Would it be possible to reuse trackDependency method? Ideally, we want to have only one function to build a RemoteDependencyData object.
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.
Possible, but I think that would make the code less consistent overall.
This dependency request code is following the same pattern as the already existing server request code. That code does not call the Client.trackRequest
method either: the helper constructs a RequestData object directly 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.
OK, let's keep it as it is.
} | ||
|
||
public trackDependency( | ||
name: string, | ||
commandName: string, | ||
target: string, |
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.
Can you add target as the last parameter and mark it as optional? This way we won't break existing users.
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.
Done.
Addressing review feedback and fixing bugs found in integration testing.
target: string = null) { | ||
|
||
if (!target && commandName) { | ||
target = url.parse(commandName).host; |
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.
Does url.parse always return an object?
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. AFAIK it never throws unless you pass it a non-string argument. An incomplete URI is just parsed as a relative path, and any invalid characters get encoded.
@@ -306,7 +315,7 @@ describe("Library/Client", () => { | |||
assert.ok(trackStub.calledOnce); | |||
var args = trackStub.args; | |||
assert.equal(args[0][0].baseType, "Microsoft.ApplicationInsights.RequestData"); | |||
assert.equal(args[0][0].baseData.responseCode, 200); |
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.
Is responseCode
gone?
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.
It's not gone, but it is not 200 anymore. This test is simulating a failed request, so the responseCode
never should have been 200. My refactor of the RequestDataHelper
/RequestParser
class fixed this bug.
I added a small comment about responseCode in |
Should this include a minor version bump in package.json, since it is a significant new feature? |
No, no need to change the version number. I usually change it when I merge from a develop to master branch. |
Closing this, because I have resubmitted as a new PR #130, to target the develop branch. |
This change adds automatic collection of dependency HTTP request data.
Please check that all the
RemoteDependencyData
fields are filled in correctly in theClientRequestParser.getDependencyData()
method. I didn't know where to find good documentation for those fields so in some cases I had to infer the correct usage by looking at other code.The GitHub web diff view unfortunately doesn't compare some files that were renamed and have only minor changes:
Requests.ts
->ServerRequests.ts
RequestDataHelper.ts
->ServerRequestParser.ts
RequestDataHelper.tests.ts
->ServerRequestParser.ts
Unit tests all pass. I also created a small test Node.js service to verify that both request and dependency telemetry is successfully uploaded. The dependencies do show up in the Application Map!