Remove Google Analytics

We are now entirely migrated to InfluxDB so can remove all GA code.
This commit is contained in:
Mike McQuaid 2023-06-16 10:33:15 +01:00
parent ab20a6e0f5
commit 75dd070395
No known key found for this signature in database
GPG Key ID: 3338A31AFDB1D829
13 changed files with 24 additions and 303 deletions

View File

@ -30,13 +30,11 @@ module Homebrew
case args.named.first
when nil, "state"
if Utils::Analytics.disabled?
puts "Analytics are disabled."
elsif Homebrew::EnvConfig.no_google_analytics?
puts "InfluxDB analytics are enabled."
puts "Google Analytics are disabled."
puts "InfluxDB analytics are disabled."
else
puts "Analytics are enabled."
puts "InfluxDB analytics are enabled."
end
puts "Google Analytics were destroyed."
when "on"
Utils::Analytics.enable!
when "off"

View File

@ -11,10 +11,6 @@ module Homebrew
module_function
ENVS = {
HOMEBREW_ADDITIONAL_GOOGLE_ANALYTICS_ID: {
description: "Additional Google Analytics tracking ID to emit user behaviour analytics to. " \
"For more information, see: <https://docs.brew.sh/Analytics>",
},
HOMEBREW_API_DOMAIN: {
description: "Use this URL as the download mirror for Homebrew JSON API. " \
"If metadata files at that URL are temporarily unavailable, " \
@ -264,7 +260,8 @@ module Homebrew
},
},
HOMEBREW_NO_ANALYTICS: {
description: "If set, do not send analytics. For more information, see: <https://docs.brew.sh/Analytics>",
description: "If set, do not send analytics. Google Analytics were destroyed. " \
"For more information, see: <https://docs.brew.sh/Analytics>",
boolean: true,
},
HOMEBREW_NO_AUTO_UPDATE: {
@ -294,11 +291,6 @@ module Homebrew
description: "If set, do not print any hints about changing Homebrew's behaviour with environment variables.",
boolean: true,
},
HOMEBREW_NO_GOOGLE_ANALYTICS: {
description: "If set, do not send analytics to Google Analytics but allow sending to Homebrew's InfluxDB " \
"analytics server. For more information, see: <https://docs.brew.sh/Analytics>",
boolean: true,
},
HOMEBREW_NO_GITHUB_API: {
description: "If set, do not use the GitHub API, e.g. for searches or fetching relevant issues " \
"after a failed install.",

View File

@ -1,22 +0,0 @@
# typed: strict
# frozen_string_literal: true
module Utils
module Analytics
class << self
sig { returns(String) }
def custom_prefix_label_google
return generic_custom_prefix_label_google if Hardware::CPU.arm?
"non-/usr/local"
end
sig { returns(String) }
def arch_label_google
return "Rosetta" if Hardware::CPU.in_rosetta2?
generic_arch_label_google
end
end
end
end

View File

@ -1,4 +0,0 @@
# typed: strict
# frozen_string_literal: true
require "extend/os/mac/utils/analytics" if OS.mac?

View File

@ -12,7 +12,7 @@ describe "brew analytics" do
brew "analytics", "off"
expect { brew "analytics", "HOMEBREW_NO_ANALYTICS" => nil }
.to output(/Analytics are disabled/).to_stdout
.to output(/analytics are disabled/i).to_stdout
.and not_to_output.to_stderr
.and be_a_success
end

View File

@ -8,42 +8,6 @@ describe Utils::Analytics do
described_class.clear_cache
end
describe "::label_google" do
let(:ci) { ", CI" if ENV["CI"] }
it "returns OS_VERSION and prefix when HOMEBREW_PREFIX is a custom prefix on intel" do
allow(Hardware::CPU).to receive(:in_rosetta2?).and_return(false)
expect(Hardware::CPU).to receive(:type).and_return(:intel).at_least(:once)
expect(Homebrew).to receive(:default_prefix?).and_return(false)
expect(described_class.label_google).to include described_class.custom_prefix_label_google
end
it "returns OS_VERSION, ARM and prefix when HOMEBREW_PREFIX is a custom prefix on arm" do
allow(Hardware::CPU).to receive(:in_rosetta2?).and_return(false)
expect(Hardware::CPU).to receive(:type).and_return(:arm).at_least(:once)
expect(Homebrew).to receive(:default_prefix?).and_return(false).at_least(:once)
expect(described_class.label_google).to include described_class.arch_label_google
expect(described_class.label_google).to include described_class.custom_prefix_label_google
end
it "returns OS_VERSION, Rosetta and prefix when HOMEBREW_PREFIX is a custom prefix on Rosetta", :needs_macos do
allow(Hardware::CPU).to receive(:in_rosetta2?).and_return(true)
expect(Hardware::CPU).to receive(:type).and_return(:intel).at_least(:once)
expect(Homebrew).to receive(:default_prefix?).and_return(false).at_least(:once)
expect(described_class.label_google).to include described_class.custom_prefix_label_google
end
it "does not include prefix when HOMEBREW_PREFIX is the default prefix" do
expect(Homebrew).to receive(:default_prefix?).and_return(true)
expect(described_class.label_google).not_to include HOMEBREW_PREFIX.to_s
end
it "includes CI when ENV['CI'] is set" do
ENV["CI"] = "1"
expect(described_class.label_google).to include "CI"
end
end
describe "::default_tags_influx" do
let(:ci) { ", CI" if ENV["CI"] }
@ -94,7 +58,6 @@ describe Utils::Analytics do
context "when ENV vars is set" do
it "returns nil when HOMEBREW_NO_ANALYTICS is true" do
ENV["HOMEBREW_NO_ANALYTICS"] = "true"
expect(described_class).not_to receive(:report_google)
expect(described_class).not_to receive(:report_influx)
described_class.report_event(:install, package_name: package_name, tap_name: tap_name,
on_request: on_request, options: options)
@ -102,7 +65,6 @@ describe Utils::Analytics do
it "returns nil when HOMEBREW_NO_ANALYTICS_THIS_RUN is true" do
ENV["HOMEBREW_NO_ANALYTICS_THIS_RUN"] = "true"
expect(described_class).not_to receive(:report_google)
expect(described_class).not_to receive(:report_influx)
described_class.report_event(:install, package_name: package_name, tap_name: tap_name,
on_request: on_request, options: options)
@ -112,7 +74,6 @@ describe Utils::Analytics do
ENV.delete("HOMEBREW_NO_ANALYTICS_THIS_RUN")
ENV.delete("HOMEBREW_NO_ANALYTICS")
ENV["HOMEBREW_ANALYTICS_DEBUG"] = "true"
expect(described_class).to receive(:report_google)
expect(described_class).to receive(:report_influx)
described_class.report_event(:install, package_name: package_name, tap_name: tap_name,
@ -120,35 +81,15 @@ describe Utils::Analytics do
end
end
it "passes to the influxdb and google methods" do
it "passes to the influxdb method" do
ENV.delete("HOMEBREW_NO_ANALYTICS_THIS_RUN")
ENV.delete("HOMEBREW_NO_ANALYTICS")
ENV["HOMEBREW_ANALYTICS_DEBUG"] = "true"
expect(described_class).to receive(:report_google).with(:event,
hash_including(ea: "#{package_name} #{options}")).once
expect(described_class).to receive(:report_influx).with(:install, hash_including(package_name: package_name,
on_request: on_request)).once
described_class.report_event(:install, package_name: package_name, tap_name: tap_name,
on_request: on_request, options: options)
end
it "sends to google twice on request" do
ENV.delete("HOMEBREW_NO_ANALYTICS_THIS_RUN")
ENV.delete("HOMEBREW_NO_ANALYTICS")
ENV["HOMEBREW_ANALYTICS_DEBUG"] = "true"
expect(described_class).to receive(:report_google).with(:event,
hash_including(ea: "#{package_name} #{options}",
ec: :install)).once
expect(described_class).to receive(:report_google).with(:event,
hash_including(ea: "#{package_name} #{options}",
ec: :install_on_request)).once
expect(described_class).to receive(:report_influx).with(:install,
hash_including(package_name: package_name,
on_request: true)).once
described_class.report_event(:install, package_name: package_name, tap_name: tap_name,
on_request: true, options: options)
end
end
describe "::report_influx" do

View File

@ -19,56 +19,6 @@ module Utils
class << self
include Context
sig { params(type: Symbol, metadata: T::Hash[Symbol, T.untyped]).void }
def report_google(type, metadata = {})
analytics_ids = ENV.fetch("HOMEBREW_ANALYTICS_IDS", "").split(",")
analytics_ids.each do |analytics_id|
args = []
# do not load .curlrc unless requested (must be the first argument)
args << "--disable" unless Homebrew::EnvConfig.curlrc?
args += %W[
--max-time 3
--user-agent #{HOMEBREW_USER_AGENT_CURL}
--data v=1
--data aip=1
--data t=#{type}
--data tid=#{analytics_id}
--data uid=n0thxg00gl3
--data an=#{HOMEBREW_PRODUCT}
--data av=#{HOMEBREW_VERSION}
]
metadata.each do |key, value|
next unless value
key = ERB::Util.url_encode key
value = ERB::Util.url_encode value
args << "--data" << "#{key}=#{value}"
end
curl = Utils::Curl.curl_executable
# Send analytics. Don't send or store any personally identifiable information.
# https://docs.brew.sh/Analytics
# https://developers.google.com/analytics/devguides/collection/protocol/v1/devguide
# https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters
if ENV["HOMEBREW_ANALYTICS_DEBUG"]
url = "https://www.google-analytics.com/debug/collect"
puts "#{curl} #{args.join(" ")} #{url}"
puts Utils.popen_read(curl, *args, url)
else
pid = fork do
exec curl, *args,
"--silent", "--output", "/dev/null",
"https://www.google-analytics.com/collect"
end
Process.detach T.must(pid)
end
end
nil
end
sig {
params(measurement: Symbol, package_name: String, tap_name: String, on_request: T::Boolean,
options: String).void
@ -125,34 +75,6 @@ module Utils
def report_event(measurement, package_name:, tap_name:, on_request:, options: "")
report_influx_event(measurement, package_name: package_name, tap_name: tap_name, on_request: on_request,
options: options)
package_and_options = package_name
if tap_name.present? && tap_name != "homebrew/core" && tap_name != "homebrew/cask"
package_and_options = "#{tap_name}/#{package_and_options}"
end
package_and_options = "#{package_and_options} #{options}" if options.present?
report_google_event(measurement, package_and_options, on_request: on_request)
end
sig { params(category: Symbol, action: String, on_request: T::Boolean).void }
def report_google_event(category, action, on_request: false)
return if not_this_run? || disabled? || Homebrew::EnvConfig.no_google_analytics?
category = "install" if category == :formula_install
report_google(:event,
ec: category,
ea: action,
el: label_google,
ev: nil)
return unless on_request
report_google(:event,
ec: :install_on_request,
ea: action,
el: label_google,
ev: nil)
end
sig {
@ -168,26 +90,9 @@ options: options)
sig { params(exception: BuildError).void }
def report_build_error(exception)
report_google_build_error(exception)
report_influx_error(exception)
end
sig { params(exception: BuildError).void }
def report_google_build_error(exception)
return if not_this_run? || disabled?
return unless exception.formula.tap
return unless exception.formula.tap.should_report_analytics?
formula_full_name = exception.formula.full_name
package_and_options = if (options = exception.options.to_a.map(&:to_s).join(" ").presence)
"#{formula_full_name} #{options}".strip
else
formula_full_name
end
report_google_event(:BuildError, package_and_options)
end
sig { params(exception: BuildError).void }
def report_influx_error(exception)
return if not_this_run? || disabled?
@ -326,39 +231,11 @@ options: options)
nil
end
sig { returns(String) }
def custom_prefix_label_google
"custom-prefix"
end
alias generic_custom_prefix_label_google custom_prefix_label_google
sig { returns(String) }
def arch_label_google
if Hardware::CPU.arm?
"ARM"
else
""
end
end
alias generic_arch_label_google arch_label_google
def clear_cache
remove_instance_variable(:@label_google) if instance_variable_defined?(:@label_google)
remove_instance_variable(:@default_tags_influx) if instance_variable_defined?(:@default_tags_influx)
remove_instance_variable(:@default_fields_influx) if instance_variable_defined?(:@default_fields_influx)
end
sig { returns(String) }
def label_google
@label_google ||= begin
os = OS_VERSION
arch = ", #{arch_label_google}" if arch_label_google.present?
prefix = ", #{custom_prefix_label_google}" unless Homebrew.default_prefix?
ci = ", CI" if ENV["CI"]
"#{os}#{arch}#{prefix}#{ci}"
end
end
sig { returns(T::Hash[Symbol, String]) }
def default_tags_influx
@default_tags_influx ||= begin
@ -499,5 +376,3 @@ options: options)
end
end
end
require "extend/os/utils/analytics"

View File

@ -33,21 +33,4 @@ setup-analytics() {
export HOMEBREW_NO_ANALYTICS_THIS_RUN="1"
return
fi
if [[ -n "${HOMEBREW_LINUX}" ]]
then
# For Homebrew on Linux's analytics.
HOMEBREW_ANALYTICS_IDS="UA-76492262-1"
else
# Otherwise, fall back to Homebrew's analytics.
HOMEBREW_ANALYTICS_IDS="UA-76679469-1"
fi
if [[ -n "${HOMEBREW_ADDITIONAL_GOOGLE_ANALYTICS_ID}" ]]
then
HOMEBREW_ANALYTICS_IDS="${HOMEBREW_ANALYTICS_IDS},${HOMEBREW_ADDITIONAL_GOOGLE_ANALYTICS_ID}"
fi
export HOMEBREW_ANALYTICS_IDS
export HOMEBREW_ANALYTICS_USER_UUID
}

View File

@ -1,45 +1,31 @@
# Anonymous Aggregate User Behaviour Analytics
# Anonymous Analytics
Homebrew gathers anonymous aggregate user behaviour analytics using InfluxDB and Google Analytics. You will be notified the first time you run `brew update` or install Homebrew. Analytics are not enabled until after this notice is shown, to ensure that you can [opt out](Analytics.md#opting-out) without ever sending analytics data.
Homebrew gathers anonymous analytics using InfluxDB. You will be notified the first time you run `brew update` or install Homebrew. Analytics are not enabled until after this notice is shown, to ensure that you can [opt out](Analytics.md#opting-out) without ever sending analytics data.
## Why?
Homebrew is provided free of charge and run entirely by volunteers in their spare time. As a result, we do not have the resources to do detailed user studies of Homebrew users to decide on how best to design future features and prioritise current work. Anonymous aggregate user analytics allow us to prioritise fixes and features based on how, where and when people use Homebrew. For example:
Homebrew is provided free of charge and run entirely by volunteers in their spare time. As a result, we do not have the resources to do detailed user studies of Homebrew users to decide on how best to design future features and prioritise current work. Anonymous analytics allow us to prioritise fixes and features based on how, where and when people use Homebrew. For example:
- If a formula is widely used and is failing often it will enable us to prioritise fixing that formula over others.
- Collecting the OS version allows us to decide which versions of macOS to prioritise for support and identify build failures that occur only on single versions.
## How Long?
Homebrew's anonymous user and event data have a 14 month retention period. This is the [lowest possible value for Google Analytics](https://support.google.com/analytics/answer/7667196).
Homebrew's anonymous analytics has a 365 day retention period in InfluxDB.
## What?
Homebrew's analytics record some shared information for every event:
- The version of Homebrew, e.g. `4.0.0`.
- The OS you are using and its version number, e.g. `macOS 13.1`.
- Whether the data is being sent from CI, e.g. `true` if the CI environment variable is set.
- Whether you are using the default install prefix (e.g. `/opt/homebrew`) or a custom one (e.g. `/home/mike/.brew`). If your prefix is custom, it will be sent as `custom-prefix` to preserve anonymity.
- Whether you are a Homebrew Developer, e.g. `true` if the `HOMEBREW_DEVELOPER` environment variable is set.
- Whether `devcmdrun` is set, e.g. `true` if you have ever run one of Homebrew's developer commands.
- Your CPU's architecture, e.g. `x86_64`.
- Whether you are using the default install prefix or a custom one, e.g. `/opt/homebrew`. If your prefix is custom, it will be sent as `custom-prefix`.
- Whether the data is being sent from CI, e.g. `1` if the CI environment variable is set.
- The analytics category, e.g. `build_error`.
- The OS you are using and its version number, e.g. `macOS 13`.
- The version of Homebrew, e.g. `4.0.0`.
For analytics sent to InfluxDB, we also record:
- Whether the `HOMEBREW_DEVELOPER` environment variable is enabled, e.g. `false`.
For analytics sent to Google Analytics, which is in the process of being phased out and removed, we also record:
- The Homebrew user agent, e.g. `Homebrew/3.3.0 (Macintosh; Intel Mac OS X 10.15.6) curl/7.64.1`.
- The [Google Analytics version](https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters#v), i.e. `1`.
- The Homebrew [analytics tracking ID](https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters#tid), i.e. `UA-76679469-1` on macOS and `UA-76492262-1` on Linux. This value is constant and is the same for all users.
- Whether the [Google Analytics anonymous IP setting](https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters#aip) is enabled, i.e. `1`.
- The Homebrew [application name](https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters#an), e.g. `Homebrew`.
- The Homebrew [analytics hit type](https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters#t), e.g. `event`.
We previously recorded but have now removed:
- A Homebrew [analytics user ID](https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters#cid), e.g. `1BAB65CC-FE7F-4D8C-AB45-B7DB5A6BA9CB`. This was generated by `uuidgen` and stored in the repository-specific Git configuration variable `homebrew.analyticsuuid` within `$(brew --repository)/.git/config`. This did not allow us to track individual users, but does enable us to accurately measure user counts versus event counts. The ID was specific to the Homebrew package manager, and did not permit Homebrew maintainers to e.g. track you across websites you visit. It was only used with Google Analytics.
All analytics data previously sent to Google Analytics has been destroyed.
Homebrew's analytics records the following different events:
@ -50,19 +36,15 @@ Homebrew's analytics records the following different events:
You can also view all the information that is sent by Homebrew's analytics by setting `HOMEBREW_ANALYTICS_DEBUG=1` in your environment. Please note this will also stop any analytics from being sent.
It is impossible for the Homebrew developers to match any particular event to any particular user, even if we had access to the Homebrew analytics user ID (which we do not). An example of the most user-specific information we can see from Google Analytics:
![Aggregate user analytics](assets/img/docs/analytics.png)
As far as we can tell it would be impossible for Google to match the randomly generated Homebrew-only analytics user ID to any other Google Analytics user ID. If Google turned evil the only thing they could do would be to lie about anonymising IP addresses and attempt to match users based on IP addresses.
It is impossible for the Homebrew developers to match any particular event to any particular user. We do not store or receive IP addresses.
## When/Where?
Homebrew's analytics are sent throughout Homebrew's execution to InfluxDB and Google Analytics over HTTPS.
Homebrew's analytics are sent throughout Homebrew's execution to InfluxDB over HTTPS.
## Who?
Summaries of installation and error analytics are [publicly available](https://formulae.brew.sh/analytics/). A JSON API is also available. The majority of Homebrew maintainers are not granted more detailed analytics data beyond these public resources.
Aggregates of analytics events are [publicly available](https://formulae.brew.sh/analytics/). A JSON API is also available. The majority of Homebrew maintainers are not granted more detailed analytics data beyond these public resources.
## How?
@ -76,12 +58,6 @@ Homebrew analytics helps us maintainers and leaving it on is appreciated. Howeve
export HOMEBREW_NO_ANALYTICS=1
```
If you are fine with analytics being sent to Homebrew's InfluxDB but not to Google Analytics, you can set:
```sh
export HOMEBREW_NO_GOOGLE_ANALYTICS=1
```
Alternatively, this will prevent analytics from ever being sent:
```sh

View File

@ -2048,9 +2048,6 @@ Note that environment variables must have a value set to be detected. For
example, run `export HOMEBREW_NO_INSECURE_REDIRECT=1` rather than just
`export HOMEBREW_NO_INSECURE_REDIRECT`.
- `HOMEBREW_ADDITIONAL_GOOGLE_ANALYTICS_ID`
<br>Additional Google Analytics tracking ID to emit user behaviour analytics to. For more information, see: <https://docs.brew.sh/Analytics>
- `HOMEBREW_API_DOMAIN`
<br>Use this URL as the download mirror for Homebrew JSON API. If metadata files at that URL are temporarily unavailable, the default API domain will be used as a fallback mirror.
@ -2246,7 +2243,7 @@ example, run `export HOMEBREW_NO_INSECURE_REDIRECT=1` rather than just
*Default:* The number of available CPU cores.
- `HOMEBREW_NO_ANALYTICS`
<br>If set, do not send analytics. For more information, see: <https://docs.brew.sh/Analytics>
<br>If set, do not send analytics. Google Analytics were destroyed. For more information, see: <https://docs.brew.sh/Analytics>
- `HOMEBREW_NO_AUTO_UPDATE`
<br>If set, do not automatically update before running some commands, e.g. `brew install`, `brew upgrade` and `brew tap`. Alternatively, run this less often by setting `HOMEBREW_AUTO_UPDATE_SECS` to a value higher than the default.
@ -2268,9 +2265,6 @@ example, run `export HOMEBREW_NO_INSECURE_REDIRECT=1` rather than just
- `HOMEBREW_NO_ENV_HINTS`
<br>If set, do not print any hints about changing Homebrew's behaviour with environment variables.
- `HOMEBREW_NO_GOOGLE_ANALYTICS`
<br>If set, do not send analytics to Google Analytics but allow sending to Homebrew's InfluxDB analytics server. For more information, see: <https://docs.brew.sh/Analytics>
- `HOMEBREW_NO_GITHUB_API`
<br>If set, do not use the GitHub API, e.g. for searches or fetching relevant issues after a failed install.

View File

@ -15,7 +15,7 @@
- [Taps (third-party repositories)](Taps.md)
- [Interesting Taps and Forks](Interesting-Taps-and-Forks.md)
- [Tips and Tricks](Tips-N'-Tricks.md)
- [Anonymous Aggregate User Behaviour Analytics](Analytics.md)
- [Anonymous Analytics](Analytics.md)
- [Querying `brew`](Querying-Brew.md)
- [C++ Standard Libraries](C++-Standard-Libraries.md)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

View File

@ -2922,12 +2922,6 @@ Many Homebrew Cask commands accept one or more \fIcask\fR arguments\. These can
Note that environment variables must have a value set to be detected\. For example, run \fBexport HOMEBREW_NO_INSECURE_REDIRECT=1\fR rather than just \fBexport HOMEBREW_NO_INSECURE_REDIRECT\fR\.
.
.TP
\fBHOMEBREW_ADDITIONAL_GOOGLE_ANALYTICS_ID\fR
.
.br
Additional Google Analytics tracking ID to emit user behaviour analytics to\. For more information, see: \fIhttps://docs\.brew\.sh/Analytics\fR
.
.TP
\fBHOMEBREW_API_DOMAIN\fR
.
.br
@ -3294,7 +3288,7 @@ Use this value as the number of parallel jobs to run when building with \fBmake\
\fBHOMEBREW_NO_ANALYTICS\fR
.
.br
If set, do not send analytics\. For more information, see: \fIhttps://docs\.brew\.sh/Analytics\fR
If set, do not send analytics\. Google Analytics were destroyed\. For more information, see: \fIhttps://docs\.brew\.sh/Analytics\fR
.
.TP
\fBHOMEBREW_NO_AUTO_UPDATE\fR
@ -3336,12 +3330,6 @@ If set, do not print \fBHOMEBREW_INSTALL_BADGE\fR on a successful build\.
If set, do not print any hints about changing Homebrew\'s behaviour with environment variables\.
.
.TP
\fBHOMEBREW_NO_GOOGLE_ANALYTICS\fR
.
.br
If set, do not send analytics to Google Analytics but allow sending to Homebrew\'s InfluxDB analytics server\. For more information, see: \fIhttps://docs\.brew\.sh/Analytics\fR
.
.TP
\fBHOMEBREW_NO_GITHUB_API\fR
.
.br