Title: Go SDK Locale: zh URL: https://sensorswave.com/docs/data-integration/server-sdks/go/ Description: Go SDK 集成指南和 API 参考 Sensors Wave Go SDK 是一个轻量级的 Go 语言事件追踪和 A/B 测试工具,支持用户事件追踪、用户档案管理和完整的 A/B 测试功能。 ## 核心功能 Go SDK 提供以下核心能力: - **事件追踪**:追踪用户事件和自定义属性 - **用户档案管理**:支持设置、增量更新、追加等完整的用户属性操作 - **A/B 测试集成**:支持功能开关、实验变量和动态配置 - **自动曝光日志**:自动记录 A/B 测试的曝光事件 - **快速启动**:支持 A/B 元数据缓存,加快启动速度 ## 安装 使用 `go get` 安装 SDK: ```bash go get github.com/sensorswave/sdk-go ``` ## 快速开始 ### 基础事件追踪 ```go package main "log" "github.com/sensorswave/sdk-go" ) func main() { // 创建客户端(最小配置) client, err := sensorswave.New( sensorswave.Endpoint("https://your-endpoint.com"), sensorswave.SourceToken("your-source-token"), ) if err != nil { log.Fatal(err) } defer client.Close() // 追踪事件 user := sensorswave.User{ LoginID: "user-123", AnonID: "device-456", } client.TrackEvent(user, "PageView", sensorswave.Properties{ "page": "/home", }) } ``` ### 启用 A/B 测试 要启用 A/B 测试,需要提供 `ABConfig`: ```go cfg := sensorswave.Config{ AB: &sensorswave.ABConfig{ ProjectSecret: "your-project-secret", }, } client, err := sensorswave.NewWithConfig( sensorswave.Endpoint("https://your-endpoint.com"), sensorswave.SourceToken("your-source-token"), cfg, ) // 现在可以使用 A/B 测试方法 result, _ := client.GetExperiment(user, "my_experiment") // 从实验结果中获取参数 btnColor := result.GetString("button_color", "blue") showBanner := result.GetBool("show_banner", false) discount := int(result.GetNumber("discount_percent", 0)) fmt.Printf("实验变体: %s, 按钮颜色: %s, 显示横幅: %v, 折扣: %d%%\n", result.Key, btnColor, showBanner, discount) ``` ## API 参考 ### 客户端接口 SDK 提供了 `Client` 接口,方法按以下类别组织: ```go type Client interface { // ========== 生命周期管理 ========== // Close 优雅地关闭客户端,刷新所有待处理事件 // 始终在应用退出前调用此方法 Close() error // ========== 用户身份 ========== // Identify 将匿名 ID 与登录 ID 关联(注册事件) // 这会创建一个 $Identify 事件,连接用户的匿名会话和认证身份 Identify(user User) error // ========== 事件追踪 ========== // TrackEvent 追踪带有属性的自定义事件 // 这是追踪用户行为的主要方法 TrackEvent(user User, event string, properties Properties) error // Track 直接提交完整填充的 Event 结构 // 用于高级场景;正常使用建议使用 TrackEvent Track(event Event) error // ========== 用户档案操作 ========== // ProfileSet 设置用户档案属性($set) // 覆盖已存在的值 ProfileSet(user User, properties Properties) error // ProfileSetOnce 仅在属性不存在时设置($set_once) // 用于记录首次值,如注册日期 ProfileSetOnce(user User, properties Properties) error // ProfileIncrement 增加数值型用户档案属性($increment) // 用于登录次数、积分等计数器 ProfileIncrement(user User, properties Properties) error // ProfileAppend 追加值到列表用户档案属性($append) // 允许列表中出现重复值 ProfileAppend(user User, properties ListProperties) error // ProfileUnion 添加唯一值到列表用户档案属性($union) // 确保列表中没有重复值 ProfileUnion(user User, properties ListProperties) error // ProfileUnset 移除用户档案属性($unset) // 从用户档案中删除指定属性 ProfileUnset(user User, propertyKeys ...string) error // ProfileDelete 删除整个用户档案($delete) // 此操作不可逆 - 请谨慎使用 ProfileDelete(user User) error // ========== A/B 测试 ========== // CheckFeatureGate 评估功能开关并返回是否通过 // 如果键不存在或不是开关类型,返回(false, nil) CheckFeatureGate(user User, key string) (bool, error) // GetFeatureConfig 为用户评估功能配置 // 如果键不存在或不是配置类型,返回空结果 GetFeatureConfig(user User, key string) (ABResult, error) // GetExperiment 为用户评估实验 // 如果键不存在或不是实验类型,返回空结果 GetExperiment(user User, key string) (ABResult, error) // GetABSpecs 将当前 A/B 测试元数据导出为 JSON // 用于缓存 A/B 配置以便在未来的会话中快速启动 // 将返回的字节传递给 ABConfig.LoadABSpecs 进行下次初始化 GetABSpecs() ([]byte, error) } ``` --- ## User 类型 > [!WARNING] > > ### 🔑 用户身份要求(必读) > > **除了 `Identify` 方法外的所有方法:** > > - ✅ `AnonID` 或 `LoginID` 至少有一个非空 > - ⚡ **如果两者都提供了,`LoginID` 优先用于用户身份识别** > > **仅对于 `Identify` 方法:** > > - ✅ **`AnonID` 和 `LoginID` 都必须非空** > - 🔗 这会创建一个 `$identify` 事件,链接匿名和认证身份 ### User 类型定义 `User` 类型表示用于事件追踪和 A/B 测试的用户身份: ```go type User struct { AnonID string // 匿名或设备 ID LoginID string // 登录用户 ID ABUserProperties map[string]interface{} // 用于 A/B 测试定向的属性 } ``` ### 使用示例 **创建不同 ID 组合的用户:** ```go // ✅ 有效:仅 LoginID(用于已登录用户) user := sensorswave.User{LoginID: "user-123"} // ✅ 有效:仅 AnonID(用于匿名用户) user := sensorswave.User{AnonID: "device-456"} // ✅ 有效:两者都有(LoginID 优先用于识别) user := sensorswave.User{ LoginID: "user-123", AnonID: "device-456", } // ❌ 无效:两者都未提供 - 这会失败 user := sensorswave.User{} ``` **对于 Identify 方法 - 两个 ID 都必需:** ```go // ✅ 正确:两个 ID 都提供了 err := client.Identify(sensorswave.User{ AnonID: "device-456", // ✅ 必需 LoginID: "user-123", // ✅ 必需 }) // ❌ 无效:只有一个 ID - Identify 会失败 err := client.Identify(sensorswave.User{ LoginID: "user-123", // ❌ 缺少 AnonID }) ``` **添加 A/B 测试定向属性:** ```go // 创建用户 user := sensorswave.User{ LoginID: "user-123", AnonID: "device-456", } // 添加 A/B 定向属性(不可变模式) user = user.WithABUserProperty(sensorswave.PspAppVer, "11.0") user = user.WithABUserProperty("is_premium", true) // 或者一次添加多个属性 user = user.WithABUserProperties(sensorswave.Properties{ sensorswave.PspAppVer: "11.0", "is_premium": true, }) ``` --- ## 事件追踪 ### Identify - 关联用户身份 将匿名 ID 与登录 ID 关联(注册事件)。 ```go user := sensorswave.User{ AnonID: "anon-123", LoginID: "user-456", } if err := client.Identify(user); err != nil { fmt.Printf("关联失败: %v\n", err) return } ``` > **重要提醒**:如果 `LoginID` 包含隐私信息(如手机号、邮箱、身份证号等),请务必在加密后再进行传输,避免敏感信息明文上报。 ### TrackEvent - 追踪自定义事件 ```go user := sensorswave.User{ AnonID: "anon-123", LoginID: "user-456", } err := client.TrackEvent(user, "Purchase", sensorswave.Properties{ "product_id": "SKU-001", "price": 99.99, "quantity": 2, }) if err != nil { fmt.Printf("追踪事件失败: %v\n", err) return } ``` ### Track - 追踪完整事件结构 ```go event := sensorswave.NewEvent("anon-123", "user-456", "PageView"). WithProperties(sensorswave.NewProperties(). Set("page", "/home"). Set("referrer", "google.com")) if err := client.Track(event); err != nil { fmt.Printf("追踪失败: %v\n", err) return } ``` --- ## 用户档案管理 用户档案用于描述用户的特征,如会员等级、注册时间、偏好设置等。与事件属性不同,用户档案会持久化保存并与用户关联。 ### ProfileSet - 设置档案属性 设置用户档案属性,如果属性已存在则覆盖。 ```go user := sensorswave.User{AnonID: "anon-123", LoginID: "user-456"} err := client.ProfileSet(user, sensorswave.Properties{ "name": "张三", "level": 5, }) if err != nil { fmt.Printf("ProfileSet 失败: %v\n", err) return } ``` ### ProfileSetOnce - 仅首次设置 设置用户档案属性,仅在属性不存在时设置。 ```go err := client.ProfileSetOnce(user, sensorswave.Properties{ "first_login_date": "2026-01-20", }) if err != nil { fmt.Printf("ProfileSetOnce 失败: %v\n", err) return } ``` ### ProfileIncrement - 增加数值属性 ```go err := client.ProfileIncrement(user, sensorswave.Properties{ "login_count": 1, "points": 100, }) if err != nil { fmt.Printf("ProfileIncrement 失败: %v\n", err) return } ``` ### ProfileAppend - 追加到列表属性 ```go err := client.ProfileAppend(user, sensorswave.ListProperties{ "tags": []any{"premium"}, }) if err != nil { fmt.Printf("ProfileAppend 失败: %v\n", err) return } ``` ### ProfileUnion - 合并列表属性 ```go err := client.ProfileUnion(user, sensorswave.ListProperties{ "categories": []any{"sports"}, }) if err != nil { fmt.Printf("ProfileUnion 失败: %v\n", err) return } ``` ### ProfileUnset - 删除属性 ```go err := client.ProfileUnset(user, "temp_field", "old_field") if err != nil { fmt.Printf("ProfileUnset 失败: %v\n", err) return } ``` ### ProfileDelete - 删除用户档案 ```go err := client.ProfileDelete(user) if err != nil { fmt.Printf("ProfileDelete 失败: %v\n", err) return } ``` > **注意**:`ProfileDelete` 会删除所有用户档案,请谨慎使用。 --- ## A/B 测试 Go SDK 内置了完整的 A/B 测试支持,可以评估功能开关、实验变量和动态配置。 ### CheckFeatureGate - 检查功能开关 检查功能开关(Boolean Toggle)是否启用。 ```go enabled, err := client.CheckFeatureGate(user, "new_feature_gate") if err != nil { fmt.Printf("评估失败: %v\n", err) return } if enabled { // 功能已启用 enableNewFeature() } else { // 功能未启用 useOldBehavior() } ``` ### GetFeatureConfig - 获取功能配置 从功能配置中获取动态配置值。 ```go result, err := client.GetFeatureConfig(user, "button_color_config") if err != nil { fmt.Printf("功能配置评估失败: %v\n", err) return } // 获取字符串值(带默认值) color := result.GetString("color", "blue") // 获取数值(带默认值) size := result.GetNumber("size", 14.0) // 获取布尔值(带默认值) enabled := result.GetBool("enabled", false) // 获取数组(带默认值) items := result.GetSlice("items", []interface{}{}) // 获取对象(带默认值) settings := result.GetMap("settings", map[string]interface{}{}) ``` ### GetExperiment - 评估实验 评估实验并获取实验变体参数。 ```go result, err := client.GetExperiment(user, "pricing_experiment") if err != nil { fmt.Printf("实验评估失败: %v\n", err) return } // 获取实验变体参数 pricingStrategy := result.GetString("strategy", "original") // 根据实验变体执行不同逻辑 switch pricingStrategy { case "original": showOriginalPricing() case "discount": discount := int(result.GetNumber("discount_percent", 0)) showDiscountPricing(discount) case "bundle": bundleSize := result.GetNumber("bundle_size", 1.0) showBundlePricing(int(bundleSize)) default: showOriginalPricing() } ``` ### 完整的 A/B 测试示例 ```go package main "fmt" "log" "github.com/sensorswave/sdk-go" ) func main() { // 创建启用 A/B 测试的客户端 cfg := sensorswave.Config{ AB: &sensorswave.ABConfig{ ProjectSecret: "your-project-secret", }, } client, err := sensorswave.NewWithConfig( sensorswave.Endpoint("https://your-endpoint.com"), sensorswave.SourceToken("your-source-token"), cfg, ) if err != nil { log.Fatal(err) } defer client.Close() // 创建用户并添加定向属性 user := sensorswave.User{ LoginID: "user-123", AnonID: "device-456", } user = user.WithABUserProperties(sensorswave.Properties{ sensorswave.PspAppVer: "11.0", "is_premium": true, }) // 评估功能开关 if enabled, _ := client.CheckFeatureGate(user, "new_ui"); enabled { fmt.Println("新 UI 已启用") } // 评估实验 result, _ := client.GetExperiment(user, "pricing_test") variant := result.GetString("variant", "control") fmt.Printf("实验变体: %s\n", variant) // 获取实验参数 discount := int(result.GetNumber("discount", 0)) fmt.Printf("折扣: %d%%\n", discount) } ``` --- ## 配置选项 ### 客户端配置 | 字段 | 说明 | 默认值 | |------|------|--------| | `TrackURIPath` | 事件上报接口路径 | `/in/track` | | `Transport` | 自定义 HTTP Transport | 默认 Transport | | `Logger` | 自定义 Logger 实现 | 控制台输出 | | `FlushInterval` | 事件刷新间隔 | 10 秒 | | `HTTPConcurrency` | 最大并发 HTTP 请求数 | 1 | | `HTTPTimeout` | HTTP 请求超时时间 | 3 秒 | | `HTTPRetry` | HTTP 请求重试次数 | 2 | | `AB` | A/B 测试配置 | nil(不启用) | ### A/B 测试配置 | 字段 | 说明 | 默认值 | |------|------|--------| | `ProjectSecret` | A/B 项目密钥(必填) | 空 | | `MetaEndpoint` | A/B 元数据服务器地址 | 空(默认使用主 Endpoint) | | `MetaURIPath` | A/B 元数据接口路径 | `/ab/all4eval` | | `MetaLoadInterval` | 元数据轮询间隔 | 30 秒(最小 30 秒) | | `LoadABSpecs` | 从 `GetABSpecs()` 缓存的规格用于快速启动 | nil | | `StickyHandler` | 自定义流量粘性处理器 | nil | | `MetaLoader` | 自定义元数据加载器 | nil | --- ## 高级用法:缓存 A/B 规格数据 为了提高启动性能,您可以缓存 A/B 规格数据并在客户端初始化时加载。 ```go // 1. 从已初始化的客户端获取规格 specs, err := client.GetABSpecs() if err != nil { // 处理错误 } // 2. 将规格保存到持久化存储(如文件、数据库、Redis) // saveToStorage(specs) // 3. 在创建新客户端时加载规格 savedSpecs := loadFromStorage() cfg := sensorswave.Config{ AB: &sensorswave.ABConfig{ ProjectSecret: "your-project-secret", LoadABSpecs: savedSpecs, // 注入缓存的规格 }, } // 客户端将立即准备好使用缓存规格进行 A/B 评估 client, err := sensorswave.NewWithConfig(..., cfg) ``` --- ## 预定义属性 SDK 为事件追踪和用户属性提供了预定义的属性常量: ```go const ( // 设备和系统属性 PspAppVer = "$app_version" // 应用版本 PspBrowser = "$browser" // 浏览器名称 PspBrowserVer = "$browser_version" // 浏览器版本 PspModel = "$model" // 设备型号 PspIP = "$ip" // IP 地址 PspOS = "$os" // 操作系统: ios/android/harmony PspOSVer = "$os_version" // 操作系统版本 // 地理位置属性 PspCountry = "$country" // 国家 PspProvince = "$province" // 省/州 PspCity = "$city" // 城市 ) ``` 在事件中使用: ```go err := client.TrackEvent(user, "purchase", sensorswave.Properties{ sensorswave.PspAppVer: "2.1.0", sensorswave.PspCountry: "US", "product_id": "SKU-001", }) ``` 在 A/B 测试中使用: ```go user = user.WithABUserProperty(sensorswave.PspAppVer, "2.1.0") user = user.WithABUserProperty(sensorswave.PspCountry, "US") ``` --- ## 完整的 API 方法参考表 ### 生命周期管理 | 方法 | 签名 | 说明 | 示例 | |------|------|------|------| | **Close** | `Close() error` | 优雅地关闭客户端并刷新待处理事件。始终在应用退出前调用。 | `defer client.Close()` | ### 用户身份 | 方法 | 签名 | 参数 | 返回值 | 说明 | |---|---|---|---|---| | **Identify** | `Identify(user User) error` | `user`: 包含 AnonID 和 LoginID 的用户 | `error` | 创建 `$Identify` 事件,链接匿名和认证身份 | ### 事件追踪 | 方法 | 签名 | 参数 | 返回值 | 说明 | |---|---|---|---|---| | **TrackEvent** | `TrackEvent(user User, event string, properties Properties) error` | `user`: 用户身份`event`: 事件名称`properties`: 事件属性 | `error` | 使用自定义属性追踪用户行为的主要方法 | | **Track** | `Track(event Event) error` | `event`: 完整填充的事件结构 | `error` | 用于高级场景的低级 API。正常使用建议使用 TrackEvent | ### 用户档案操作 | 方法 | 签名 | 说明 | 使用场景 | |---|---|---|---| | **ProfileSet** | `ProfileSet(user User, properties Properties) error` | 设置或覆盖档案属性 | 更新用户名、邮箱、设置 | | **ProfileSetOnce** | `ProfileSetOnce(user User, properties Properties) error` | 仅在属性不存在时设置 | 记录注册日期、首次来源 | | **ProfileIncrement** | `ProfileIncrement(user User, properties Properties) error` | 增加数值型档案属性 | 登录次数、积分、分数 | | **ProfileAppend** | `ProfileAppend(user User, properties ListProperties) error` | 追加到列表档案属性(允许重复) | 添加购买历史、活动日志 | | **ProfileUnion** | `ProfileUnion(user User, properties ListProperties) error` | 添加唯一值到列表档案属性 | 添加兴趣、标签、分类 | | **ProfileUnset** | `ProfileUnset(user User, propertyKeys ...string) error` | 移除指定档案属性 | 清除临时或已废弃的字段 | | **ProfileDelete** | `ProfileDelete(user User) error` | 删除整个用户档案(不可逆) | GDPR 数据删除请求 | ### A/B 测试 | 方法 | 签名 | 参数 | 返回值 | 说明 | |---|---|---|---|---| | **CheckFeatureGate** | `CheckFeatureGate(user User, key string) (bool, error)` | `user`: 用户, `key`: 开关键 | `bool, error` | 评估功能开关。如果键不存在或类型错误,返回(false, nil) | | **GetFeatureConfig** | `GetFeatureConfig(user User, key string) (ABResult, error)` | `user`: 用户, `key`: 配置键 | `ABResult, error` | 评估功能配置。如果键不存在或类型错误,返回空结果 | | **GetExperiment** | `GetExperiment(user User, key string) (ABResult, error)` | `user`: 用户, `key`: 实验键 | `ABResult, error` | 评估实验。如果键不存在或类型错误,返回空结果 | | **GetABSpecs** | `GetABSpecs() ([]byte, error)` | 无 | `[]byte, error` | 将当前 A/B 元数据导出为 JSON,用于缓存和快速启动 | --- ## 最佳实践 ### 1. 错误处理 在生产环境中,建议对所有 SDK 调用进行错误处理: ```go func trackUserEvent(userID, eventName string, props Properties) { if err := client.TrackEvent(user, eventName, props); err != nil { // 记录错误,但不影响主业务流程 log.Printf("追踪事件失败: %v", err) // 可选:将失败的事件发送到备用存储 // saveToBackupQueue(userID, eventName, props) } } ``` ### 2. 资源管理 使用 `defer` 确保客户端正确关闭: ```go func main() { client, err := sensorswave.New(...) if err != nil { log.Fatal(err) } defer client.Close() // 确保程序退出时关闭客户端 // 使用客户端... } ``` ### 3. A/B 测试用户上下文 构建完整的用户上下文以获得准确的实验分配: ```go func buildABUser(userID string) sensorswave.User { user := sensorswave.User{ LoginID: userID, } // 添加 A/B 测试定向属性 user = user.WithABUserProperties(sensorswave.Properties{ sensorswave.PspAppVer: getAppVersion(), sensorswave.PspOS: "linux", "is_premium": checkIsPremium(userID), "registration_date": getUserRegistrationDate(userID), }) return user } ``` ### 3. 事件名称命名规范 统一采用**大写驼峰格式(PascalCase)**命名事件: ```go // ✅ 推荐做法:大写驼峰格式 client.TrackEvent(user, "PageView", props) client.TrackEvent(user, "Purchase", props) client.TrackEvent(user, "AddToCart", props) client.TrackEvent(user, "UserRegistered", props) client.TrackEvent(user, "ButtonClicked", props) // ❌ 避免使用:小写下划线(除非有历史数据) client.TrackEvent(user, "page_view", props) client.TrackEvent(user, "purchase", props) client.TrackEvent(user, "add_to_cart", props) ``` **命名规范说明**: - **推荐**:采用大写驼峰格式(如 `PageView`、`AddToCart`、`UserRegistered`) - **历史兼容**:如果已存在历史埋点数据采用小写下划线风格,可继续保持该风格,但要**保持统一** - **关键点**:无论采用哪种风格,**尽量保证同一个项目下的事件命名规范必须保持一致** ### 4. 事件属性命名 遵循一致的命名规范,使用 `snake_case`: ```go // 推荐做法 sensorswave.Properties{ "product_id": "SKU-001", "order_amount": 99.99, "user_tier": "premium", } // 避免使用 sensorswave.Properties{ "ProductID": "SKU-001", // 避免大写 "orderAmount": 99.99, // 避免驼峰命名 } ``` ### 5. 批量操作 对于需要频繁更新用户档案的场景,使用增量更新而非多次设置: ```go user := sensorswave.User{ LoginID: userID, } // 不推荐:多次网络请求 client.ProfileSet(user, sensorswave.Properties{"login_count": 1}) client.ProfileSet(user, sensorswave.Properties{"points": 100}) // 推荐:一次网络请求 client.ProfileIncrement(user, sensorswave.Properties{ "login_count": 1, "points": 100, }) ``` --- ## 常见问题 ### 为什么事件没有上报成功? 检查以下几点: 1. **Endpoint 和 Token 是否正确**:确认 `Endpoint` 和 `SourceToken` 配置正确 2. **网络连接**:检查服务端是否能访问数据上报地址 3. **错误日志**:查看 SDK 的错误输出,启用 Logger 进行调试 4. **超时设置**:检查 `HTTPTimeout` 设置是否合理 5. **并发限制**:检查 `HTTPConcurrency` 是否需要调整 ### 如何避免阻塞主业务流程? SDK 内部使用异步刷新机制,但建议在单独的 goroutine 中处理错误: ```go go func() { if err := client.TrackEvent(user, "EventName", props); err != nil { log.Printf("追踪事件失败: %v", err) } }() ``` ### A/B 测试评估结果不一致? 确保: 1. **用户属性一致**:每次评估时使用的 `ABUserProperties` 保持一致 2. **使用粘性处理器**:对于需要保持一致性的场景,配置 `StickyHandler` 3. **元数据已更新**:检查 `MetaLoadInterval` 设置,确保元数据已刷新 --- ## 相关文档 - [埋点方案选择](../tracking-strategy.mdx):了解服务端埋点和客户端埋点的优劣 - [如何正确的标识用户](../user-identification.mdx):用户身份识别的最佳实践 - [数据模型](../data-model.mdx):理解 Sensors Wave 的数据结构 - [事件和属性](../events-and-properties.mdx):事件设计规范和最佳实践 --- **最后更新时间**:2026 年 1 月 29 日 **SDK 仓库**:[github.com/sensorswave/sdk-go](https://github.com/sensorswave/sdk-go) **许可证**:查看 LICENSE 文件