Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ga): upgrade measurement protocol to GA4 from UA #2

Merged
merged 2 commits into from
Nov 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
example/tracker-id.txt
example/tracker-id.txt
**/.idea
64 changes: 39 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,58 +2,72 @@

Track and monitor your Go programs for free with Google Analytics

The `ga` package is essentially a Go wrapper around the [Google Analytics - Measurement Protocol](https://developers.google.com/analytics/devguides/collection/protocol/v1/reference)

**Warning** This package is 95% generated from the [Parameter Reference](https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters) so it may contain bugs - please report them. GA allows "10 million hits per month per property" and will reject requests after that.
The `ga` package is essentially a Go wrapper around the [Google Analytics - Measurement Protocol (Google Analytics 4)](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference?client_type=gtag)

### Install

```
go get -v github.com/jpillora/go-ogle-analytics
go get -v github.com/openebs/go-ogle-analytics
```

### API

Create a new `client` and `Send()` a 'pageview', 'screenview', 'event', 'transaction', 'item', 'social', 'exception' or 'timing' event.

#### http://godoc.org/github.com/jpillora/go-ogle-analytics
Create a new `client` and `Send()` an 'event'.

### Quick Usage

1. Log into GA and create a new property and note its Tracker ID
1. Log into GA and create a new property and note its Measurement ID

1. Create a `ga-test.go` file
2. Create a `ga-test.go` file

``` go
package main

import "github.com/jpillora/go-ogle-analytics"
import (
gaClient "github.com/openebs/go-ogle-analytics/client"
gaEvent "github.com/openebs/go-ogle-analytics/event"
)

func main() {
client, err := ga.NewClient("UA-XXXXXXXX-Y")
if err != nil {
panic(err)
}

err = client.Send(ga.NewEvent("Foo", "Bar").Label("Bazz"))
if err != nil {
panic(err)
}

println("Event fired!")
}
client, err := gaClient.NewMeasurementClient(
gaClient.WithApiSecret("yourApiSecret"),
gaClient.WithMeasurementId("G-yourMeasurementClient"),
gaClient.WithClientId("uniqueUserId-000000001"),
)
if err != nil {
panic(err)
}

event, err := gaEvent.NewOpenebsEvent(
gaEvent.WithCategory("Foo"),
gaEvent.WithAction("Bar"),
gaEvent.WithLabel("Baz"),
gaEvent.WithValue(19072023),
)
if err != nil {
panic(err)
}

err = client.Send(event)
if err != nil {
panic(err)
}

println("Event fired!")
}

```

1. In GA, go to Real-time > Events
3. In GA, go to Report > Realtime

1. Run `ga-test.go`
4. Run `ga-test.go`

```
$ go run ga-test.go
Event fired!
```

1. Watch as your event appears
5. Watch as your event appears

![foo-ga](https://cloud.githubusercontent.com/assets/633843/5979585/023fc580-a8fd-11e4-803a-956610bcc2e2.png)

Expand Down
91 changes: 0 additions & 91 deletions client.go

This file was deleted.

87 changes: 87 additions & 0 deletions client/build.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package client

import (
"context"
"net"
"net/http"
"regexp"

"github.com/openebs/lib-csi/pkg/common/errors"
)

var measurementIDMatcher = regexp.MustCompile(`^G-[a-zA-Z0-9]+$`)

type MeasurementClientOption func(*MeasurementClient) error

type MeasurementClient struct {
HttpClient *http.Client
apiSecret string
measurementId string
clientId string
}

func NewMeasurementClient(opts ...MeasurementClientOption) (*MeasurementClient, error) {
dialer := &net.Dialer{
Resolver: &net.Resolver{
PreferGo: true,
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
dialer := net.Dialer{}
return dialer.DialContext(ctx, network, "8.8.8.8:53")
},
},
}
c := &MeasurementClient{
HttpClient: &http.Client{
Transport: &http.Transport{
DialContext: dialer.DialContext,
},
},
}

var err error
for _, opt := range opts {
err = opt(c)
if err != nil {
return nil, errors.Wrap(err, "failed to build MeasurementClient")
}
}

return c, nil
}

func WithApiSecret(secret string) MeasurementClientOption {
return func(s *MeasurementClient) error {
if len(secret) == 0 {
return errors.Errorf("failed to set api_secret: secret is an empty string")
}

s.apiSecret = secret
return nil
}
}

func WithMeasurementId(measurementId string) MeasurementClientOption {
return func(s *MeasurementClient) error {
if len(measurementId) == 0 {
return errors.Errorf("failed to set measurement_id: id is an empty string")
}

if !measurementIDMatcher.MatchString(measurementId) {
return errors.Errorf("Invalid measurement_id: %s", measurementId)
}

s.measurementId = measurementId
return nil
}
}

func WithClientId(clientId string) MeasurementClientOption {
return func(s *MeasurementClient) error {
if len(clientId) == 0 {
return errors.Errorf("failed to set client_id: id is an empty string")
}

s.clientId = clientId
return nil
}
}
61 changes: 61 additions & 0 deletions client/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package client

import (
"bytes"
"encoding/json"
"net/http"
"net/url"

"github.com/openebs/lib-csi/pkg/common/errors"

"github.com/openebs/go-ogle-analytics/event"
"github.com/openebs/go-ogle-analytics/payload"
)

func (c *MeasurementClient) Copy() *MeasurementClient {
cpy := *c
return &cpy
}

func (c *MeasurementClient) addFields(v url.Values) {
v.Add("api_secret", c.apiSecret)
v.Add("measurement_id", c.measurementId)
}

func (c *MeasurementClient) Send(event *event.OpenebsEvent) error {

client := c.Copy()

dataPayload, err := payload.NewPayload(
payload.WithClientId(client.clientId),
payload.WithOpenebsEvent(event),
)

if err != nil {
return err
}
jsonData, err := json.Marshal(dataPayload)
if err != nil {
return err
}

gaUrl := "https://www.google-analytics.com/mp/collect"

req, err := http.NewRequest("POST", gaUrl, bytes.NewReader(jsonData))
v := req.URL.Query()
client.addFields(v)
req.URL.RawQuery = v.Encode()

req.Header.Set("Content-Type", "application/json")

resp, err := client.HttpClient.Do(req)
if err != nil {
return err
}

if resp.StatusCode/100 != 2 {
return errors.Errorf("Rejected by Google with code %d", resp.StatusCode)
}

return nil
}
19 changes: 0 additions & 19 deletions conv.go

This file was deleted.

Loading