-
Notifications
You must be signed in to change notification settings - Fork 3k
Record and report success metrics #15084
Conversation
e1c7ae8 to
04d7c2f
Compare
df3ff9e to
3e6fe06
Compare
|
Nice idea! Is this implemented on the registry yet? |
othiym23
left 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.
Here's what I've got thus far – nothing in here should be construed as a blocker to merging this, but I am curious about your responses.
lib/utils/error-handler.js
Outdated
| if (!npm.config || !npm.config.loaded) return | ||
|
|
||
| // kill any outstanding stats reporter if it hasn't finished yet | ||
| if (npm.statsProcess) npm.statsProcess.kill('SIGKILL') |
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 get the intent of this, but given that the main of lib/utils/send-metrics.js has to require most of npm to find the stats, what happens when somebody runs a quick command like npm -v?
Should this instead be using a trappable signal, like SIGINT or SIGTERM, and at least giving send-metrics a chance to clean up after itself?
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.
send-metrics is explicitly written with the intent that killing it should be safe. I consider it more important that we be certain that there aren't any lingering processes (that are maybe updating the stats file) then that send-metrics not be interrupted.
lib/utils/send-metrics.js
Outdated
| function main () { | ||
| var fs = require('fs') | ||
| var path = require('path') | ||
| var npm = require('../npm.js') |
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 makes metrics delivery a much more heavyweight process than it would be otherwise. How difficult would it be to just load the bits of config we need to bootstrap a registry client and create it directly? If the detached client were lighter-weight, I'd be less concerned about killing it with fire in the parent process's exit handler.
lib/utils/send-metrics.js
Outdated
| npm.load({}, function (err) { | ||
| if (err) return | ||
| npm.registry.config.retry.retries = 0 | ||
| npm.registry.sendAnonymousCLIMetrics(metricsRegistry, cliMetrics, function (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.
The situation I'm specifically concerned about is the metrics reporter getting killed between this line and clearing out the stats file below, which seems like a distinct possibility for faster-running comands (and is something that's likely to be exacerbated rather than mitigated by performance improvements to the rest of the CLI). Reporting the same stats multiple times isn't the worst thing in the world, but it seems like something we should be able to guard against more robustly.
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 is intended to be allowed, per the spec I wrote, without double counting. This is why the metrics file gets a unique ID that's changed only when sending the CLI metrics is successful.
Without a succesfull send we update the metrics file without changing that unique ID. This way the registry can just count the most recent set of data with that unique ID.
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.
Excellent! Consider my comment withdrawn, then.
| }) | ||
|
|
||
| test('record success', function (t) { | ||
| common.npm(['install', '--no-send-metrics', 'success'], conf, function (err, code, stdout, stderr) { |
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 like that the tests don't rely on specific knowledge of what the metrics file looks like. This is a good set of integration tests! But running three installs to check one piece of behavior feels like a lot of overhead for the results. I don't think whacking this (and the next) install to speed up the test is a blocker, but if it could be done without a huge amount of trouble, it would be beneficial.
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.
One set of behavior? I'm not sure I follow? There's no way to tell the installer to do all (or any) of these things all in one go…
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 hadn't considered the fact that you're testing that the stats are being written correctly. With that in mind, my objection makes much less sense. Never mind!
lib/install.js
Outdated
| var statsFile = path.join(npm.config.get('cache'), 'anonymous-cli-stats.json') | ||
| var stats | ||
| try { | ||
| stats = JSON.parse(fs.readFileSync(statsFile)) |
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 it premature to abstract the metrics out into a defined interface, if our goal is to introduce more supportability metrics over time? In other words, would it make sense to put the metrics object into a module that can be required as needed across the project (or maybe hung off a process.on listener, a la numbat)?
I'm fine with shipping this as-is, but it does seem like this is something we're going to want to change pretty soon, and having it behind a defined interface from the get-go therefore makes a certain amount of sense.
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've just pushed a little refactor that moves all of the existing logic into a single file (without changing any of those interfaces), which makes this a bit clearer.
At the moment the entire interface that npm has is saveMetrics with true or false. And yeah, that's clearly not going to be sufficient going forward.
On the other hand, I think I'm inclined to leave it as is until we add another metric. My inclination is to wait until we have a concrete addition that necessitates the change in interface. Right now it'd be pretty hypothetical. We can make educated guesses, sure, but front loading the work uh... hmm, doesn't right?
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 that the latest refactor is more than sufficient for now. Thanks for the clear answers!
3e6fe06 to
4dfb41e
Compare
|
Coverage increased (+0.08%) to 85.723% when pulling 4dfb41ee54c016ea205e4b7010041784d9fd9fd1 on iarna/anon-cli-stats into 87afc8b on release-next. |
|
After this round of review, this is ready to merge. 🐑🚀🔥 |
|
Coverage increased (+0.1%) to 85.743% when pulling 5c893ac30ce3cfc85eb1f1a10a007325daec6501 on iarna/anon-cli-stats into 87afc8b on release-next. |
|
@legodude17 Nope. You can see the issue for tracking that part over here → npm/registry#11 |
5c893ac to
38e5c4f
Compare
See: #12529