Skip to content

Commit

Permalink
fix: better code style and unit testing (#1)
Browse files Browse the repository at this point in the history
* refactor(logger): make it more flexible

* fix: better performance code and unit testing

* fix: more unit testing

* fix: more unit testing

* ci: update ci

* feat: release 1.0.1

* docs: add changelog
  • Loading branch information
YoloMao authored Nov 11, 2024
1 parent c98565c commit 6467ada
Show file tree
Hide file tree
Showing 23 changed files with 1,390 additions and 243 deletions.
25 changes: 25 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Unit Testing

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
go-version: ["1.21", "1.22", "1.23"]

steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}

- name: Run tests
run: |
go test -v -cover ./...
34 changes: 34 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Publish

on:
release:
types: [published]

jobs:
publish:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.21'

- name: Module tidy
run: go mod tidy

- name: Publish to proxy
env:
GOPROXY: proxy.golang.org
run: |
# 确保所有依赖项都正确安装
go list -m all
# 使用 go list 命令请求版本的代理缓存,以便 proxy.golang.org 缓存新版本
go list -m github.com/growingio/growingio-sdk-go@${GITHUB_REF#refs/tags/}
echo "Published to proxy.golang.org"
- name: Confirm the module is available on proxy.golang.org
run: |
curl -sL https://proxy.golang.org/github.com/growingio/growingio-sdk-go/@v/${GITHUB_REF#refs/tags/}.info
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@

## [1.0.1](https://github.com/growingio/growingio-sdk-go/tree/v1.0.1) (2024-11-11)

### Changed

* 更好的调用性能
* 提升代码质量
* 添加单元测试

## [1.0.0](https://github.com/growingio/growingio-sdk-go/tree/v1.0.0) (2024-10-23)

### Features

* 支持埋点事件
* 支持用户属性事件
* 支持维度表上报

59 changes: 31 additions & 28 deletions analytics.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ var lock = make(chan struct{}, 1)
func InitAnalytics(config *Config) error {
lock <- struct{}{}
defer func() { <-lock }()
// create the logger before any calls are made
logger.NewLogger()

if core.InitializedSuccessfully {
err := errors.New("initialization failed, already initialized")
Expand Down Expand Up @@ -75,6 +77,7 @@ func InitAnalytics(config *Config) error {
core.RoutineCount = config.BatchConfig.RoutineCount
core.MaxCacheSize = config.BatchConfig.MaxCacheSize
core.InitBatch()
core.RunBatch()
}

core.InitializedSuccessfully = true
Expand All @@ -98,85 +101,85 @@ func InitAnalyticsByConfigFile(file string) error {
return InitAnalytics(config)
}

func TrackCustomEvent(builder *CustomEventBuilder) error {
func TrackCustomEvent(b *CustomEventBuilder) error {
if !core.InitializedSuccessfully {
err := errors.New("TrackCustomEvent failed, GrowingAnalytics has not been initialized")
logger.Error(err, "Please init GrowingAnalytics first")
return err
}

if len(builder.EventName) == 0 {
if len(b.EventName) == 0 {
err := errors.New("TrackCustomEvent failed, EventName is empty")
logger.Error(err, "Please enter eventName for customEvent")
return err
}

if len(builder.AnonymousId)+len(builder.LoginUserId) == 0 {
if len(b.AnonymousId)+len(b.LoginUserId) == 0 {
err := errors.New("TrackCustomEvent failed, AnonymousId and LoginUserId are empty")
logger.Error(err, "Both AnonymousId and LoginUserId are empty. Please enter at least one of them")
return err
}

b := core.EventBuilder{
EventName: builder.EventName,
EventTime: builder.EventTime,
AnonymousId: builder.AnonymousId,
LoginUserId: builder.LoginUserId,
LoginUserKey: builder.LoginUserKey,
Attributes: builder.Attributes,
builder := &core.EventBuilder{
EventName: b.EventName,
EventTime: b.EventTime,
AnonymousId: b.AnonymousId,
LoginUserId: b.LoginUserId,
LoginUserKey: b.LoginUserKey,
Attributes: b.Attributes,
}
b.BuildCustomEvent()
core.BuildCustomEvent(builder)
return nil
}

func TrackUser(builder *UserEventBuilder) error {
func TrackUser(b *UserEventBuilder) error {
if !core.InitializedSuccessfully {
err := errors.New("TrackUser failed, GrowingAnalytics has not been initialized")
logger.Error(err, "Please init GrowingAnalytics first")
return err
}

if len(builder.LoginUserId) == 0 {
if len(b.LoginUserId) == 0 {
err := errors.New("TrackUser failed, LoginUserId is empty")
logger.Error(err, "Please enter loginUserId for user")
return err
}

b := core.EventBuilder{
EventTime: builder.EventTime,
AnonymousId: builder.AnonymousId,
LoginUserId: builder.LoginUserId,
LoginUserKey: builder.LoginUserKey,
Attributes: builder.Attributes,
builder := &core.EventBuilder{
EventTime: b.EventTime,
AnonymousId: b.AnonymousId,
LoginUserId: b.LoginUserId,
LoginUserKey: b.LoginUserKey,
Attributes: b.Attributes,
}
b.BuildUserLoginEvent()
core.BuildUserLoginEvent(builder)
return nil
}

func SubmitItem(builder *ItemBuilder) error {
func SubmitItem(b *ItemBuilder) error {
if !core.InitializedSuccessfully {
err := errors.New("SubmitItem failed, GrowingAnalytics has not been initialized")
logger.Error(err, "Please init GrowingAnalytics first")
return err
}

if len(builder.ItemId) == 0 {
if len(b.ItemId) == 0 {
err := errors.New("SubmitItem failed, ItemId is empty")
logger.Error(err, "Please enter itemId for item")
return err
}

if len(builder.ItemKey) == 0 {
if len(b.ItemKey) == 0 {
err := errors.New("SubmitItem failed, ItemKey is empty")
logger.Error(err, "Please enter itemKey for item")
return err
}

b := core.EventBuilder{
ItemId: builder.ItemId,
ItemKey: builder.ItemKey,
Attributes: builder.Attributes,
builder := &core.EventBuilder{
ItemId: b.ItemId,
ItemKey: b.ItemKey,
Attributes: b.Attributes,
}
b.BuildItemEvent()
core.BuildItemEvent(builder)
return nil
}
6 changes: 5 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@ require (
github.com/go-logr/logr v1.4.2
github.com/go-logr/stdr v1.2.2
github.com/golang/snappy v0.0.4
github.com/stretchr/testify v1.9.0
google.golang.org/protobuf v1.35.1
gopkg.in/yaml.v3 v3.0.1
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/google/go-cmp v0.6.0 // indirect
gopkg.in/yaml.v3 v3.0.1
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
)
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
Expand All @@ -7,6 +9,12 @@ github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
Expand Down
15 changes: 15 additions & 0 deletions hack/boilerplate/boilerplate.generatego.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// @license
// Copyright (C) 2024 Beijing Yishu Technology Co., Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
10 changes: 10 additions & 0 deletions internal/core/.mockery.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
dir: .
filename: "mock_{{.InterfaceName | snakecase}}_test.go"
boilerplate-file: ../../hack/boilerplate/boilerplate.generatego.txt
inpackage: true
with-expecter: true
packages:
github.com/growingio/growingio-sdk-go/internal/core:
interfaces:
Batch:
Request:
67 changes: 39 additions & 28 deletions internal/core/batch.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,25 @@ const defaultRoutineCount = 16
const defaultMaxCacheSize = 10240

var (
BatchEnable bool
MaxSize int
FlushAfter int

BatchEnable bool
MaxSize int
FlushAfter int
RoutineCount int
MaxCacheSize int

batch *Batch
bInst Batch
routine chan struct{}
)

type Batch struct {
routine chan struct{}
events chan *protobuf.EventV3Dto
items chan *protobuf.ItemDto
type Batch interface {
pushEvent(event *protobuf.EventV3Dto)
pushItem(item *protobuf.ItemDto)
pop()
}

type batch struct {
events chan *protobuf.EventV3Dto
items chan *protobuf.ItemDto
}

func InitBatch() {
Expand All @@ -59,56 +64,62 @@ func InitBatch() {
MaxCacheSize = defaultMaxCacheSize
}

batch = &Batch{
events: make(chan *protobuf.EventV3Dto, MaxCacheSize),
items: make(chan *protobuf.ItemDto, MaxCacheSize),
routine: make(chan struct{}, RoutineCount),
}
routine = make(chan struct{}, RoutineCount)
bInst = NewBatch()
}

go send()
func RunBatch() {
go run(bInst)
}

func NewBatch() Batch {
return &batch{
events: make(chan *protobuf.EventV3Dto, MaxCacheSize),
items: make(chan *protobuf.ItemDto, MaxCacheSize),
}
}

func send() {
func run(b Batch) {
for {
batch.routine <- struct{}{}
routine <- struct{}{}
go func() {
defer func() { <-batch.routine }()
batch.pop()
defer func() { <-routine }()
b.pop()
}()
}
}

func (batch *Batch) pushEvent(event *protobuf.EventV3Dto) {
batch.events <- event
func (b *batch) pushEvent(event *protobuf.EventV3Dto) {
b.events <- event
}

func (batch *Batch) pushItem(item *protobuf.ItemDto) {
batch.items <- item
func (b *batch) pushItem(item *protobuf.ItemDto) {
b.items <- item
}

func (batch *Batch) pop() {
func (b *batch) pop() {
var events []*protobuf.EventV3Dto
var items []*protobuf.ItemDto

L:
Query:
for {
select {
case e := <-batch.events:
case e := <-b.events:
events = append(events, e)
if len(events) >= MaxSize {
logger.Debug("sending events due to exceeding limit", "count", len(events), "limit", MaxSize)
sendEvents(events)
events = make([]*protobuf.EventV3Dto, 0)
}
case i := <-batch.items:
case i := <-b.items:
items = append(items, i)
if len(items) >= MaxSize {
logger.Debug("sending items due to exceeding limit", "count", len(items), "limit", MaxSize)
sendItems(items)
items = make([]*protobuf.ItemDto, 0)
}
case <-time.After(time.Duration(FlushAfter) * time.Second):
break L
break Query
}
}

Expand Down
Loading

0 comments on commit 6467ada

Please sign in to comment.