chore(metrics): have a better identifier fallback (#1130)

Andrey Nering created

Change summary

internal/event/event.go      | 12 +-------
internal/event/identifier.go | 49 ++++++++++++++++++++++++++++++++++++++
2 files changed, 51 insertions(+), 10 deletions(-)

Detailed changes

internal/event/event.go 🔗

@@ -9,7 +9,6 @@ import (
 	"runtime"
 
 	"github.com/charmbracelet/crush/internal/version"
-	"github.com/denisbrodbeck/machineid"
 	"github.com/posthog/posthog-go"
 )
 
@@ -39,6 +38,7 @@ func Init() {
 		slog.Error("Failed to initialize PostHog client", "error", err)
 	}
 	client = c
+	distinctId = getDistinctId()
 }
 
 // send logs an event to PostHog with the given event name and properties.
@@ -47,7 +47,7 @@ func send(event string, props ...any) {
 		return
 	}
 	err := client.Enqueue(posthog.Capture{
-		DistinctId: distinctId(),
+		DistinctId: distinctId,
 		Event:      event,
 		Properties: pairsToProps(props...).Merge(baseProps),
 	})
@@ -105,11 +105,3 @@ func pairsToProps(props ...any) posthog.Properties {
 func isEven(n int) bool {
 	return n%2 == 0
 }
-
-func distinctId() string {
-	id, err := machineid.ProtectedID("charm")
-	if err != nil {
-		return "crush-cli"
-	}
-	return id
-}

internal/event/identifier.go 🔗

@@ -0,0 +1,49 @@
+package event
+
+import (
+	"crypto/hmac"
+	"crypto/sha256"
+	"encoding/hex"
+	"fmt"
+	"net"
+
+	"github.com/denisbrodbeck/machineid"
+)
+
+var distinctId string
+
+const (
+	hashKey    = "charm"
+	fallbackId = "unknown"
+)
+
+func getDistinctId() string {
+	if id, err := machineid.ProtectedID(hashKey); err == nil {
+		return id
+	}
+	if macAddr, err := getMacAddr(); err == nil {
+		return hashString(macAddr)
+	}
+	return fallbackId
+}
+
+func getMacAddr() (string, error) {
+	interfaces, err := net.Interfaces()
+	if err != nil {
+		return "", err
+	}
+	for _, iface := range interfaces {
+		if iface.Flags&net.FlagUp != 0 && iface.Flags&net.FlagLoopback == 0 && len(iface.HardwareAddr) > 0 {
+			if addrs, err := iface.Addrs(); err == nil && len(addrs) > 0 {
+				return iface.HardwareAddr.String(), nil
+			}
+		}
+	}
+	return "", fmt.Errorf("no active interface with mac address found")
+}
+
+func hashString(str string) string {
+	hash := hmac.New(sha256.New, []byte(str))
+	hash.Write([]byte(hashKey))
+	return hex.EncodeToString(hash.Sum(nil))
+}