revert: 设计原因移除 report 包,采用 utils/counter
This commit is contained in:
parent
a31369abbe
commit
7cbe5c4805
|
@ -17,7 +17,6 @@ mindmap
|
||||||
/notify 通知功能接口定义
|
/notify 通知功能接口定义
|
||||||
/planner 策划相关工具目录
|
/planner 策划相关工具目录
|
||||||
/pce 配置导表功能实现
|
/pce 配置导表功能实现
|
||||||
/report 数据埋点及上报功能
|
|
||||||
/server 网络服务器支持
|
/server 网络服务器支持
|
||||||
/cross 内置跨服功能实现
|
/cross 内置跨服功能实现
|
||||||
/router 内置路由器功能实现
|
/router 内置路由器功能实现
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
# Report
|
|
||||||
用于数据上报,其中数据埋点是线程安全的
|
|
||||||
|
|
||||||
# 全局埋点 GlobalBuried
|
|
||||||
全局埋点适用于活跃用户数、用户总量等全局的数据统计
|
|
||||||
|
|
||||||
# 数据埋点 DataBuried
|
|
||||||
数据埋点适合进行用户数据、交易数据等存在多id情况的数据统计
|
|
||||||
|
|
||||||
# 跨进程上报
|
|
||||||
通常数据埋点会占用一些系统资源而妨碍主进程的运行,这时候可以通过将上报工作独立出来减轻主进程负担
|
|
||||||
|
|
||||||
默认情况下的埋点数据是存储在执行进程的内存中的,可以通过可选项自定义存储位置,例如`Redis`
|
|
||||||
|
|
||||||
> 实现思路,以`Redis`为例:
|
|
||||||
> - 在主进程创建埋点,并将数据读写更改为`Redis`
|
|
||||||
> - 上报进程中创建上报器,按照特定策略从`Redis`读取数据进行上报
|
|
|
@ -1,60 +0,0 @@
|
||||||
package report
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/kercylan98/minotaur/utils/concurrent"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewDataBuried 创建一个数据埋点
|
|
||||||
func NewDataBuried[DataID comparable, Data any](name string, hitLogic HitLogic[Data], options ...DataBuriedOption[DataID, Data]) *DataBuried[DataID, Data] {
|
|
||||||
buried := &DataBuried[DataID, Data]{
|
|
||||||
name: name,
|
|
||||||
data: concurrent.NewBalanceMap[DataID, Data](),
|
|
||||||
hitLogic: hitLogic,
|
|
||||||
}
|
|
||||||
buried.setData = func(id DataID, data Data) {
|
|
||||||
buried.data.Set(id, data)
|
|
||||||
}
|
|
||||||
buried.getData = func(id DataID) Data {
|
|
||||||
return buried.data.Get(id)
|
|
||||||
}
|
|
||||||
for _, option := range options {
|
|
||||||
option(buried)
|
|
||||||
}
|
|
||||||
return buried
|
|
||||||
}
|
|
||||||
|
|
||||||
// DataBuried 数据埋点
|
|
||||||
// - 数据埋点通常用于统计不同类型的数据,例如用户数据、商城数据等
|
|
||||||
type DataBuried[DataID comparable, Data any] struct {
|
|
||||||
name string
|
|
||||||
data *concurrent.BalanceMap[DataID, Data]
|
|
||||||
hitLogic HitLogic[Data]
|
|
||||||
getData func(DataID) Data
|
|
||||||
setData func(id DataID, data Data)
|
|
||||||
rw sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetName 获取名称
|
|
||||||
func (slf *DataBuried[DataID, Data]) GetName() string {
|
|
||||||
return slf.name
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hit 命中数据埋点
|
|
||||||
func (slf *DataBuried[DataID, Data]) Hit(id DataID, data Data) {
|
|
||||||
slf.rw.Lock()
|
|
||||||
defer slf.rw.Unlock()
|
|
||||||
slf.setData(id, slf.hitLogic(slf.getData(id), data))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetData 获取数据
|
|
||||||
func (slf *DataBuried[DataID, Data]) GetData(id DataID) Data {
|
|
||||||
slf.rw.RLock()
|
|
||||||
defer slf.rw.RUnlock()
|
|
||||||
return slf.getData(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSize 获取已触发该埋点的id数量
|
|
||||||
func (slf *DataBuried[DataID, Data]) GetSize() int {
|
|
||||||
return slf.data.Size()
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
package report
|
|
||||||
|
|
||||||
type DataBuriedOption[DataID comparable, Data any] func(buried *DataBuried[DataID, Data])
|
|
||||||
|
|
||||||
// WithDataBuriedStorage 通过特定的存储模式创建数据埋点
|
|
||||||
// - 默认情况下埋点数据存储在内存中
|
|
||||||
// - 使用该方式可以将埋点存储存储在其他如数据库、消息队列中
|
|
||||||
func WithDataBuriedStorage[DataID comparable, Data any](getData func(id DataID) Data, setData func(id DataID, data Data)) DataBuriedOption[DataID, Data] {
|
|
||||||
return func(buried *DataBuried[DataID, Data]) {
|
|
||||||
buried.getData = getData
|
|
||||||
buried.setData = setData
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
// Package report 提供了对数据埋点及上报的实现
|
|
||||||
package report
|
|
|
@ -1,51 +0,0 @@
|
||||||
package report
|
|
||||||
|
|
||||||
import "sync"
|
|
||||||
|
|
||||||
// NewGlobalBuried 创建一个全局埋点
|
|
||||||
func NewGlobalBuried[Data any](name string, hitLogic HitLogic[Data], options ...GlobalBuriedOption[Data]) *GlobalBuried[Data] {
|
|
||||||
buried := &GlobalBuried[Data]{
|
|
||||||
name: name,
|
|
||||||
hitLogic: hitLogic,
|
|
||||||
}
|
|
||||||
buried.setData = func(data Data) {
|
|
||||||
buried.data = data
|
|
||||||
}
|
|
||||||
buried.getData = func() Data {
|
|
||||||
return buried.data
|
|
||||||
}
|
|
||||||
for _, option := range options {
|
|
||||||
option(buried)
|
|
||||||
}
|
|
||||||
return buried
|
|
||||||
}
|
|
||||||
|
|
||||||
// GlobalBuried 全局埋点
|
|
||||||
// - 全局埋点适用于活跃用户数等统计
|
|
||||||
type GlobalBuried[Data any] struct {
|
|
||||||
name string
|
|
||||||
data Data
|
|
||||||
hitLogic HitLogic[Data]
|
|
||||||
getData func() Data
|
|
||||||
setData func(data Data)
|
|
||||||
rw sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetName 获取名称
|
|
||||||
func (slf *GlobalBuried[Data]) GetName() string {
|
|
||||||
return slf.name
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hit 命中数据埋点
|
|
||||||
func (slf *GlobalBuried[Data]) Hit(data Data) {
|
|
||||||
slf.rw.Lock()
|
|
||||||
defer slf.rw.Unlock()
|
|
||||||
slf.setData(slf.hitLogic(slf.getData(), data))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetData 获取数据
|
|
||||||
func (slf *GlobalBuried[Data]) GetData() Data {
|
|
||||||
slf.rw.RLock()
|
|
||||||
defer slf.rw.RUnlock()
|
|
||||||
return slf.getData()
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
package report
|
|
||||||
|
|
||||||
type GlobalBuriedOption[Data any] func(buried *GlobalBuried[Data])
|
|
||||||
|
|
||||||
// WithGlobalBuriedStorage 通过特定的存储模式创建全局埋点
|
|
||||||
// - 默认情况下埋点数据存储在内存中
|
|
||||||
// - 使用该方式可以将埋点存储存储在其他如数据库、消息队列中
|
|
||||||
func WithGlobalBuriedStorage[DataID comparable, Data any](getData func() Data, setData func(data Data)) GlobalBuriedOption[Data] {
|
|
||||||
return func(buried *GlobalBuried[Data]) {
|
|
||||||
buried.getData = getData
|
|
||||||
buried.setData = setData
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
package report
|
|
||||||
|
|
||||||
import "github.com/kercylan98/minotaur/utils/generic"
|
|
||||||
|
|
||||||
// HitLogic 埋点命中逻辑
|
|
||||||
// - data: 当前数据
|
|
||||||
// - input: 新输入的数据
|
|
||||||
// - return: 设置当前数据
|
|
||||||
type HitLogic[Data any] func(data Data, input Data) Data
|
|
||||||
|
|
||||||
// WithHitLogicCustomize 通过自定义命中处理逻辑处理命中事件
|
|
||||||
// - 通过对旧数据和新数据的处理,将返回的值作为新的数据值
|
|
||||||
func WithHitLogicCustomize[Data any](logic func(data Data, input Data) Data) HitLogic[Data] {
|
|
||||||
return func(data Data, input Data) Data {
|
|
||||||
return logic(data, input)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithHitLogicCover 通过覆盖原数值的方式处理命中事件
|
|
||||||
func WithHitLogicCover[Data any]() HitLogic[Data] {
|
|
||||||
return func(data Data, input Data) Data {
|
|
||||||
return input
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithHitLogicOverlay 通过数值叠加的方式处理命中事件
|
|
||||||
// - 例如原始值为100,新输入为200,最终结果为300
|
|
||||||
func WithHitLogicOverlay[Data generic.Number]() HitLogic[Data] {
|
|
||||||
return func(data Data, input Data) Data {
|
|
||||||
return data + input
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
package report
|
|
||||||
|
|
||||||
import "github.com/kercylan98/minotaur/utils/timer"
|
|
||||||
|
|
||||||
func NewReporter(reportHandle func() error, options ...ReporterOption) *Reporter {
|
|
||||||
reporter := &Reporter{
|
|
||||||
reportHandle: reportHandle,
|
|
||||||
}
|
|
||||||
for _, option := range options {
|
|
||||||
option(reporter)
|
|
||||||
}
|
|
||||||
if reporter.ticker == nil {
|
|
||||||
reporter.ticker = timer.GetTicker(50)
|
|
||||||
}
|
|
||||||
for _, strategy := range reporter.strategies {
|
|
||||||
strategy(reporter)
|
|
||||||
}
|
|
||||||
return reporter
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reporter 数据上报器
|
|
||||||
type Reporter struct {
|
|
||||||
ticker *timer.Ticker
|
|
||||||
strategies []ReporterStrategy
|
|
||||||
reportHandle func() error
|
|
||||||
errorHandle func(reporter *Reporter, err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Report 上报
|
|
||||||
func (slf *Reporter) Report() error {
|
|
||||||
return slf.reportHandle()
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
package report
|
|
||||||
|
|
||||||
import "github.com/kercylan98/minotaur/utils/timer"
|
|
||||||
|
|
||||||
type ReporterOption func(reporter *Reporter)
|
|
||||||
|
|
||||||
// WithReporterTicker 通过特定的定时器创建上报器
|
|
||||||
func WithReporterTicker(ticker *timer.Ticker) ReporterOption {
|
|
||||||
return func(reporter *Reporter) {
|
|
||||||
reporter.ticker = ticker
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithReporterStrategies 通过特定上报策略进行创建
|
|
||||||
func WithReporterStrategies(strategies ...ReporterStrategy) ReporterOption {
|
|
||||||
return func(reporter *Reporter) {
|
|
||||||
reporter.strategies = append(reporter.strategies, strategies...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func WithReporterErrorHandle(errorHandle func(reporter *Reporter, err error)) ReporterOption {
|
|
||||||
return func(reporter *Reporter) {
|
|
||||||
reporter.errorHandle = errorHandle
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
package report
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/kercylan98/minotaur/utils/timer"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ReporterStrategy 上报器策略
|
|
||||||
type ReporterStrategy func(reporter *Reporter)
|
|
||||||
|
|
||||||
// StrategyLoop 循环上报
|
|
||||||
// - 将在创建后上报一次,并且在每隔一段时间后继续上报
|
|
||||||
func StrategyLoop(t time.Duration) ReporterStrategy {
|
|
||||||
return func(reporter *Reporter) {
|
|
||||||
reporter.ticker.Loop(fmt.Sprintf("ReportStrategyLoop_%d", t.Milliseconds()), timer.Instantly, t, timer.Forever, func() {
|
|
||||||
if err := reporter.Report(); err != nil && reporter.errorHandle != nil {
|
|
||||||
reporter.errorHandle(reporter, err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// StrategyFixedTime 将在每天的固定时间上报
|
|
||||||
func StrategyFixedTime(hour, min, sec int) ReporterStrategy {
|
|
||||||
return func(reporter *Reporter) {
|
|
||||||
now := time.Now()
|
|
||||||
current := now.Unix()
|
|
||||||
next := time.Date(now.Year(), now.Month(), now.Day(), hour, min, sec, 0, now.Location())
|
|
||||||
target := next.Unix()
|
|
||||||
if current >= target {
|
|
||||||
next = next.AddDate(0, 0, 1)
|
|
||||||
target = next.Unix()
|
|
||||||
}
|
|
||||||
reporter.ticker.Loop(fmt.Sprintf("ReportStrategyFixedTime_%d_%d_%d", hour, min, sec), time.Duration(target-current)*time.Second, 24*time.Hour, -1, func() {
|
|
||||||
if err := reporter.Report(); err != nil && reporter.errorHandle != nil {
|
|
||||||
reporter.errorHandle(reporter, err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue