This gem is used to report opinionated statistics about modularization to DataDog and other observability systems.
This gem assumes you've correctly configured the packs gem so that pack_stats knows where to find your code's packs.
The gem reports metrics per-team, where each team is configured based on metadata included in Packwerk package.yml files.
Define your teams as described in the Code Team - Package Based Ownership documentation.
The main method to this gem is PackStats#report_to_datadog!. Refer to the Sorbet signature for this method for the exact types to be passed in.
This is an example of how to use this API:
PackStats.report_to_datadog!(## A properly initialized `Dogapi::Client`# Example: Dogapi::Client.new(ENV.fetch('DATADOG_API_KEY')#datadog_client: datadog_client,## Time attached to the metrics# Example: Time.now#report_time: report_time## This is used to determine what files to look at for building statistics about what types of files are packaged, componentized, or unpackaged.# This is an array of `Pathname`. `Pathname` can be relative or absolute paths.## Example: source_code_pathnames = Pathname.glob('./**/**.rb')#source_code_pathnames: source_code_pathnames,## A file is determined to be componentized if it exists in any of these directories.# This is an array of `Pathname`. `Pathname` can be relative or absolute paths.## Example: [Pathname.new("./gems")]#componentized_source_code_locations: componentized_source_code_locations,)It's recommended to run this in CI on the main/development branch so each new commit has metrics emitted for it.
require'pack_stats'defreport(verbose:,max_enforcements: false)ignored_paths=Pathname.glob('spec/fixtures/**/**')source_code_pathnames=Pathname.glob('{app,components,lib,packs,spec}/**/**').select(&:file?) - ignored_pathsPackStats.report_to_datadog!(datadog_client: Dogapi::Client.new(ENV.fetch('DATADOG_API_KEY')),app_name: Rails.application.class.module_parent_name,source_code_pathnames: source_code_pathnames,verbose: verbose,max_enforcements: max_enforcements)endnamespace(:pack_stats)dodesc('Publish pack_stats to datadog. ' \
'Example: bin/rails "pack_stats:upload"')task(:upload,[:verbose]=>:environment)do |_,args|
verbose=args[:verbose] == 'true' || false# First send without any changes, tagging metrics with max_enforcements:falsereport(verbose: verbose,max_enforcements: false)# At Gusto, it's useful to be able to view the dashboard as if all enforce_x were set to true.# To do this, we rewrite all `package.yml` files with `enforce_dependencies` and `enforce_privacy`# set to true, then bin/packwerk update-todo.old_packages=ParsePackwerk.allold_packages.eachdo |package|
new_package=package.with(enforce_dependencies: true,enforce_privacy: true)ParsePackwerk.write_package_yml!(new_package)endPackwerk::Cli.new.execute_command(['update-todo'])# Now we reset it back so that the protection values are the same as the native packwerk configurationold_packages.eachdo |package|
ParsePackwerk.write_package_yml!(package)end# Then send after maxing out enforcements, tagging metrics with max_enforcements:truereport(verbose: verbose,max_enforcements: true)endendRight now this tool sends metrics to DataDog only. However, if you want to use this with other tools, you can call PackStats.get_metrics(...) to get generic metrics that you can then send to whatever observability provider you use.
We recommend the use of the dashboard that is shipped with this gem. You can create a new dashboard and then click "import dashboard JSON" to get a jump start on tracking your metrics. Note you may want to make some tweaks to these dashboards to better fit your organization's circumstances and goals.