Problem/Motivation
It would be really useful to be able to expose data from Commerce, such as:
- Orders and the state they are in.
- Revenue from orders.
- The number of products.
Proposed resolution
Add a submodule that exposes these metrics, and anything else in the future in the realm of Drupal Commerce.
Since calculating current metrics can be slow (several seconds of database queries on my test site with nearly 1 million order records), we need to break this into two phases:
1. A hook_rebuild implementation that creates the metrics, so we catch any changes in data applied by update hooks.
2. Event subscribers that increment and decrement the metrics.
The following metrics are exposed:
commerce_orders_revenue_total, with labels for order state, currency, administrative area, and site name.
commerce_orders_total, with labels for state, administrative area, and site name.
commerce_products_total, counting product entities, with labels for type and site name.
commerce_orders_revenue_total{state="completed",currency="USD",administrative_area="AA",site_name="Example.com"} 123
commerce_orders_total{state="canceled",administrative_area="MA",site_name="Example.com"} 74
commerce_products_total{type="egift_card",site_name="Example.com"} 23
Remaining tasks
- Do we want to push the RebuildableInterface up to the base module? The idea of rebuilding metrics after a deployment seems likely to be useful.
- We would like to be able to add labels for site specific data. I'm thinking that could be a separate issue that fires an event when building a metric?
User interface changes
None (so far!)
API changes
None.
Data model changes
None.
Issue fork prometheus_metrics-3556711
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #3
deviantintegral commentedComment #4
deviantintegral commentedComment #5
deviantintegral commentedI've got unit and kernel tests in place, and they identified some deprecated code. They also identified that any exception rebuilding metrics would cause them all to stop, so I changed that to have one catch per method call.
While I have a few questions, I think this is ready for review!
Comment #6
deranga commentedThanks for opening this feature request and the work you've put into it. I'll try to put aside some time this weekend to review and get back to you.
Comment #7
plopescThe code looks great!
I’ve added a few comments regarding Drupal core compatibility.
While this is outside the scope of the current issue, the simplest long-term solution might be to create a new module release that drops support for Drupal core versions earlier than 10.3. This would allow the removal of several core-version checks currently present in the parent module.
The module maintainers can decide how to proceed — either by updating this merge request to ensure compatibility with older Drupal versions, or by opening a separate MR aimed at stabilizing the codebase for Drupal 10.3+ and merging this one afterward.
Another option would be to address the compatibility changes directly in this MR, though that would likely expand the scope more than necessary.
Comment #8
deranga commentedI've made a few changes.
Comment #9
deviantintegral commentedAll your changes look good to me. I pushed up edits based on the review.
We haven't deployed this yet, but I'm imagining a future scenario where a developer makes changes to orders directly in the database in an update hook. This could be in a contrib module, but more likely I'd guess custom code. I don't know if they're realize they need to rebuild metrics at the same time.
The other scenario I can think of is on managed hosts like Acquia and Pantheon. They often restart containers after a deployment, and don't support persistence in Redis or Memcache. In that scenario, the data is gone, but a cache rebuild will get it back up.
On the site I'm testing with, it has nearly 1 million orders, and takes around 2.5 seconds to rebuild all the stats. I'm not sure if we need to consider the case with 10 million orders or more.
Comment #10
deviantintegral commentedI enabled gitlab testing and fixed some tests. I think this is ready for another look!
Comment #11
deranga commentedI've made a few changes, and cleaned up a few bits.
I've added an item to the configuration form that allows the admin/ user to optionally wipe and rebuild metrics. This dispatches an event that can be optionally subscribed to. I've implemented an example of this in the parent module, would it be possible for you to do the same for the sub module and remove it from happening on cache rebuild?
I've done it this way as I'm not keen on the idea of it being automatically triggered on cache rebuild.
If you feel we need it to happen on cache rebuild, then my suggestion is that we add an option for this behaviour to the parent module config form, and we dispatch the same event from the parent module when the cache is rebuilt if that option has been enabled.
I've cleaned up for PHPCS and PHPStan and added some pre-commit hooks to try and keep it clean; let me know if this causes issues and I'll separate that out from the repo.
Comment #12
deranga commentedMade several more changes.
Let me know if any questions or issues.
Think this is now ready for a final review before merging. Would appreciate someone else taking a look if feasible.
Comment #13
deviantintegral commentedYour changes all good to me. I've pushed up one text change, because Pantheon notably doesn't commit to long-term persistence of data in Redis. They don't back it to disk at all, and only support it as a cache. Look OK?
I'm developing with ddev locally, so these are fine in that they just don't do anything if I don't install the hooks. However, I did notice some changes that don't follow Drupal standards, such as the array indentation in `\Drupal\Tests\prometheus_metrics_commerce\Kernel\OrderRevenueTest::createOrder`. Honestly, it's fine by me to finish the issue and clean up formatting in a followup.
Comment #16
deranga commentedComment #18
deranga commented