Skip to content

Commit d8edd37

Browse files
authored
Merge pull request #18 from database-playground/pan93412/dbp-91-在後端導入-posthog
DBP-91: 在後端導入 PostHog
2 parents 75329b0 + 07b9006 commit d8edd37

File tree

18 files changed

+211
-110
lines changed

18 files changed

+211
-110
lines changed

cmd/backend/dependencies.go

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"github.com/database-playground/backend-v2/internal/workers"
3131
"github.com/gin-contrib/cors"
3232
"github.com/gin-gonic/gin"
33+
"github.com/posthog/posthog-go"
3334
"github.com/redis/rueidis"
3435
"github.com/vektah/gqlparser/v2/ast"
3536
"go.uber.org/fx"
@@ -50,6 +51,31 @@ func ApqCache(redisClient rueidis.Client) graphql.Cache[string] {
5051
return apq.NewCache(redisClient, 24*time.Hour)
5152
}
5253

54+
func PostHogClient(lifecycle fx.Lifecycle, cfg config.Config) (posthog.Client, error) {
55+
if cfg.PostHog.APIKey == nil || cfg.PostHog.Host == nil {
56+
slog.Warn("PostHog client is not initialized, because you did not configure a PostHog API key and a host.")
57+
return nil, nil
58+
}
59+
60+
client, err := posthog.NewWithConfig(
61+
*cfg.PostHog.APIKey,
62+
posthog.Config{
63+
Endpoint: *cfg.PostHog.Host,
64+
},
65+
)
66+
if err != nil {
67+
return nil, err
68+
}
69+
70+
lifecycle.Append(fx.StopHook(func() {
71+
if err := client.Close(); err != nil {
72+
slog.Info("failed to close PostHog client", "error", err)
73+
}
74+
}))
75+
76+
return client, nil
77+
}
78+
5379
// GqlgenHandler creates a gqlgen handler.
5480
func GqlgenHandler(
5581
entClient *ent.Client,
@@ -85,8 +111,8 @@ func UserAccountContext(entClient *ent.Client, storage auth.Storage, eventServic
85111
}
86112

87113
// EventService creates an events.EventService.
88-
func EventService(entClient *ent.Client) *events.EventService {
89-
return events.NewEventService(entClient)
114+
func EventService(entClient *ent.Client, posthogClient posthog.Client) *events.EventService {
115+
return events.NewEventService(entClient, posthogClient)
90116
}
91117

92118
// SubmissionService creates a submission.SubmissionService.

cmd/backend/server.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ func main() {
2020
EventService,
2121
SubmissionService,
2222
ApqCache,
23+
PostHogClient,
2324
AnnotateService(AuthService),
2425
GqlgenHandler,
2526
fx.Annotate(

docs/config.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,13 @@ Google OAuth 的「已授權的重新導向 URI」應包含 `https://HOST/api/au
5757
## SQL Runner
5858

5959
- `SQL_RUNNER_URI`[SQL Runner API](https://github.com/database-playground/sqlrunner-v2) 的連線 URL,如 `https://sqlrunner.dbplay.app`。部署說明可參見 [Usage > Starting the service](https://github.com/database-playground/sqlrunner-v2/tree/main?tab=readme-ov-file#starting-the-service)
60+
61+
## PostHog 設定
62+
63+
PostHog 是一個產品統計平台。這個專案使用 [posthog-go](https://posthog.com/docs/libraries/go) 做後端的 event 寫入。
64+
65+
如果不填寫 API Key 則代表不送出任何統計。
66+
67+
- `POSTHOG_API_KEY`: PostHog 的 API key。可以在 PostHog 的 Settings > Project > General > Project API key 中取得。
68+
- `POSTHOG_HOST`: PostHog API 的主機。可以在 PostHog 的 Settings > Project > General > Web snippet 中的 `api_host` 取得。
69+
- e.g. `https://us.i.posthog.com`

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ require (
1414
github.com/jackc/pgx/v5 v5.7.6
1515
github.com/joho/godotenv v1.5.1
1616
github.com/mattn/go-sqlite3 v1.14.28
17+
github.com/posthog/posthog-go v1.6.10
1718
github.com/redis/rueidis v1.0.66
1819
github.com/samber/lo v1.51.0
1920
github.com/stretchr/testify v1.11.1

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
215215
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
216216
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
217217
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
218+
github.com/posthog/posthog-go v1.6.10 h1:OA6bkiUg89rI7f5cSXbcrH5+wLinyS6hHplnD92Pu/M=
219+
github.com/posthog/posthog-go v1.6.10/go.mod h1:LcC1Nu4AgvV22EndTtrMXTy+7RGVC0MhChSw7Qk5XkY=
218220
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
219221
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
220222
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=

graph/user.resolvers_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func (m *mockAuthStorage) Peek(ctx context.Context, token string) (auth.TokenInf
5454
func NewTestResolver(t *testing.T, entClient *ent.Client, authStorage auth.Storage) *Resolver {
5555
t.Helper()
5656

57-
eventService := events.NewEventService(entClient)
57+
eventService := events.NewEventService(entClient, nil)
5858
sqlrunner := testhelper.NewSQLRunnerClient(t)
5959

6060
submissionService := submission.NewSubmissionService(entClient, eventService, sqlrunner)

httpapi/auth/introspect_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func setupTestAuthServiceWithDatabase(t *testing.T) (*AuthService, *mockAuthStor
5454

5555
storage := newMockAuthStorageForIntrospect()
5656
cfg := config.Config{}
57-
eventService := events.NewEventService(entClient)
57+
eventService := events.NewEventService(entClient, nil)
5858
useraccount := useraccount.NewContext(entClient, storage, eventService)
5959

6060
authService := NewAuthService(entClient, storage, cfg, useraccount)

httpapi/auth/revoke_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ func setupTestAuthService(t *testing.T) (*AuthService, *mockAuthStorage) {
7676
entClient := testhelper.NewEntSqliteClient(t)
7777
storage := newMockAuthStorage()
7878
cfg := config.Config{}
79-
eventService := events.NewEventService(entClient)
79+
eventService := events.NewEventService(entClient, nil)
8080
useraccount := useraccount.NewContext(entClient, storage, eventService)
8181

8282
authService := NewAuthService(entClient, storage, cfg, useraccount)

internal/config/models.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ type Config struct {
1717
GAuth GAuthConfig `envPrefix:"GAUTH_"`
1818
Server ServerConfig `envPrefix:"SERVER_"`
1919
SqlRunner SqlRunnerConfig `envPrefix:"SQL_RUNNER_"`
20+
PostHog PostHogConfig `envPrefix:"POSTHOG_"`
2021
}
2122

2223
func (c Config) Validate() error {
@@ -32,6 +33,12 @@ func (c Config) Validate() error {
3233
if err := c.Server.Validate(); err != nil {
3334
return fmt.Errorf("SERVER: %w", err)
3435
}
36+
if err := c.SqlRunner.Validate(); err != nil {
37+
return fmt.Errorf("SQL_RUNNER: %w", err)
38+
}
39+
if err := c.PostHog.Validate(); err != nil {
40+
return fmt.Errorf("POSTHOG: %w", err)
41+
}
3542

3643
return nil
3744
}
@@ -147,3 +154,20 @@ func (c SqlRunnerConfig) Validate() error {
147154

148155
return nil
149156
}
157+
158+
type PostHogConfig struct {
159+
APIKey *string `env:"API_KEY"`
160+
Host *string `env:"HOST"`
161+
}
162+
163+
func (c PostHogConfig) Validate() error {
164+
if c.APIKey != nil && *c.APIKey == "" {
165+
return errors.New("POSTHOG_API_KEY cannot be empty")
166+
}
167+
168+
if c.Host != nil && *c.Host == "" {
169+
return errors.New("POSTHOG_HOST cannot be empty")
170+
}
171+
172+
return nil
173+
}

internal/events/constants.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,7 @@ const (
99
EventTypeLogoutAll EventType = "logout_all"
1010

1111
EventTypeSubmitAnswer EventType = "submit_answer"
12+
13+
// Internal usage
14+
EventTypeGrantPoint EventType = "grant_point"
1215
)

0 commit comments

Comments
 (0)