이벤트 로그 전송
개요
애널리틱스에 이벤트 로그를 전송할 수 있습니다. 전송할 이벤트를 구성할 때는 이벤트 템플릿에서 제공하는 이벤트 구조와 Hive Axyl 자동 수집 여부를 확인하세요.
추가로 분석이 필요한 이벤트 로그는 클라이언트 또는 서버에서 전송할 수 있습니다.
1. Hive Axyl 클라이언트 전송
Hive Axyl을 통해 클라이언트에서 이벤트 로그를 전송하는 방법입니다. CollectClientLogAsync()를 호출해 앱에서 발생한 이벤트를 애널리틱스로 전송합니다. 호출하기 전에 이벤트마다 로그 이벤트를 만들어 목록 하나에 담습니다. 전체 API는 IAnalyticsService를 참고하세요.
1.1. 로그 이벤트 준비
로그 이벤트는 앱에서 일어난 이벤트 하나를 기록한 데이터이며, 애널리틱스가 수집하고 분석하는 단위입니다. 로그 이벤트 하나에는 이벤트 이름, 발생 시각, 앱이 정한 속성이 들어갑니다.
로그 이벤트는 ClientLogEvent 객체로 만들어 ClientLogCollectRequest의 LogBody 목록에 담습니다. 목록에 담은 로그 이벤트는 요청 한 번에 모두 전송합니다. LogBody가 비어 있어도 SDK는 요청을 그대로 보내므로, 로그 이벤트를 하나 이상 담아 호출하세요. ClientLogEvent의 각 필드는 아래와 같이 준비합니다.
1.1.1. EventName
EventName에는 어떤 이벤트가 발생했는지 나타내는 이벤트 이름을 문자열로 넣습니다. 모든 로그 이벤트에 반드시 넣어야 하는 값입니다. 이름은 앱이 정합니다. 예를 들어 사용자의 레벨이 올랐을 때 보내는 로그 이벤트라면 levelup_log처럼 정합니다.
1.1.2. EventTime
EventTime에는 이벤트가 발생한 시각을 DateTimeOffset 값으로 넣습니다. 모든 로그 이벤트에 반드시 넣어야 하는 값입니다. 이벤트가 발생한 시점에 DateTimeOffset.Now로 현재 시각을 얻어 넣으세요. 로그 이벤트를 모아 두었다가 나중에 전송하더라도 전송 시각이 아닌 이벤트 발생 시각을 넣어야 합니다.
SDK는 EventTime을 인터넷 표준 날짜·시각 표기 형식인 RFC 3339 문자열로 바꿔 전송합니다. 이 문자열에는 협정 세계시(UTC)와의 시차도 포함됩니다. EventTime을 지정하지 않아도 SDK는 오류로 처리하지 않고 DateTimeOffset의 기본값을 그대로 전송하므로 반드시 직접 지정하세요. 아래는 EventTime 값별로 전송되는 문자열의 예시입니다.
- 한국 시간 2026년 1월 1일 오전 7시 34분 42초:
2026-01-01T07:34:42.0000000+09:00 - 지정하지 않은 경우:
0001-01-01T00:00:00.0000000+00:00
1.1.3. DeviceId
DeviceId에는 앱이 로그인 요청에 넣는 DeviceKey와 정확히 같은 값을 넣어야 합니다. 로그 이벤트를 보낸 기기와 인증에 사용한 기기가 일치해야 데이터를 정확하게 분석하기 때문입니다.
DeviceKey는 게스트, 유저네임, 외부 인증 제공자, 커스텀 계정 등 계정 유형과 관계없이 로그인 요청에 넣는 기기 식별 값입니다. SDK는 DeviceId를 자동으로 채우지 않고 DeviceKey를 저장하지도 않습니다. 아래 순서로 앱이 직접 값을 넣으세요.
- 앱이 직접 만들어 기기에 저장해 둔
DeviceKey를 불러오세요.DeviceKey는 앱을 처음 실행할 때 한 번 만들어 저장해 두는 값이므로, 로그인하기 전에도 이미 기기에 있습니다. 만들고 보관하는 방법은 deviceKey를 참조하세요. - 불러온 값을 그대로
DeviceId에 넣으세요. 로그인 전후와 관계없이 모든 로그 이벤트에 같은 값을 넣고,DeviceId에 넣을 값을 새로 만들지 마세요.
1.1.4. UserId
UserId는 사용자 식별자를 담는 선택 필드입니다. 넣지 않으면 이 필드 없이 로그 이벤트를 전송합니다.
1.1.5. IdentifierProvider
IdentifierProvider는 식별자 제공자를 나타내는 선택 필드입니다. 서버가 항상 hive로 덮어쓰므로 지정하지 마세요.
1.1.6. 이벤트 속성
이벤트 이름과 발생 시각 외에 분석에 필요한 정보는 AdditionalProperties에 이벤트 속성으로 추가합니다. 서버는 속성 내용을 해석하지 않고 수집하므로, 속성을 미리 정의할 필요 없이 앱이 이름과 개수를 정해 보내면 됩니다.
AdditionalProperties는 속성 이름을 키로, 속성 값을 값으로 담는 딕셔너리입니다. SDK는 요청 본문을 데이터 교환 형식인 JSON으로 만들어 전송합니다. 이때 각 속성은 이벤트 이름과 같은 수준의 필드로 기록됩니다. 기본값은 빈 딕셔너리이며, 비어 있으면 속성을 전송하지 않습니다.
1.1.6.1. 속성 값 형식
속성 값에는 화면에 표시할 텍스트가 아니라 JSON 값 자체를 문자열로 넣으세요. 예를 들어 문자열 값은 큰따옴표까지 포함해 넣어야 합니다.
| 값의 종류 | C# 코드에 넣는 값 | 전송되는 JSON |
|---|---|---|
| 숫자 | "42" | 42 |
| 문자열 | "\"gold\"" | "gold" |
| 불리언 | "true" | true |
| 배열 | "[1,2]" | [1,2] |
| 객체 | "{\"a\":1}" | {"a":1} |
| JSON null | "null" | null |
| C# null | null | null |
Warning
SDK는 속성 값을 검증하지 않고 요청 본문에 그대로 기록합니다. 문자열 값 gold를 "\"gold\"" 대신 "gold"로 넣는 것처럼 올바른 JSON 값이 아닌 값이 하나라도 있으면 요청 본문 전체가 잘못된 JSON이 됩니다. 같은 요청에 담은 다른 로그 이벤트도 잘못된 본문으로 함께 전송됩니다.
1.1.6.2. 피해야 할 속성 이름
eventTime, eventName, deviceId, userId, identifierProvider는 ClientLogEvent의 필드를 전송할 때 쓰는 이름입니다. 이 이름을 속성 이름으로 쓰면 한 로그 이벤트에 같은 이름의 필드가 두 번 전송될 수 있으므로 사용하지 마세요.
1.2. 이벤트 로그 전송
CollectClientLogAsync()를 호출해 준비한 로그 이벤트 목록을 전송합니다. 서버가 로그를 수집하면 Success를 반환하며, 응답 데이터는 없습니다. App ID는 초기화할 때 지정한 값을 SDK가 요청마다 자동으로 전달하므로 요청에 넣지 않아도 됩니다.
1.2.1. 로그인 전후 전송
CollectClientLogAsync()는 사용자가 로그인하기 전과 로그인한 후 모두 같은 방법으로 호출합니다. 로그인은 애널리틱스 사용의 필수 조건이 아니므로, 앱을 실행한 직후처럼 로그인하기 전에 발생한 이벤트도 전송합니다. 로그인 여부에 따라 달라지는 것은 SDK가 요청에 담는 인증 정보뿐입니다.
- 로그인 전: 인증 토큰 없이 요청 전송
- 로그인 세션 활성화 후: 세션의 인증 토큰을 요청에 자동으로 포함해 전송
로그인 세션이 활성화되어 있으면 서버는 요청에 담긴 인증 토큰으로 로그를 보낸 사용자를 판별합니다. 인증 토큰은 SDK가 넣으므로 앱에서 요청에 직접 넣지 않아도 됩니다.
1.2.2. 호출 파라미터
| 필드명 | 타입 | 필수 여부 | 설명 |
|---|---|---|---|
request | ClientLogCollectRequest | Required | 전송할 로그 이벤트 목록을 담은 요청 |
context | ApiCallContext? | Optional | 호출 단위 설정 객체입니다. 생략하면 기본값이 사용됩니다. |
request에 null을 넘기면 ArgumentNullException이 발생합니다.
1.2.2.1. ClientLogCollectRequest
| 필드명 | 타입 | 필수 여부 | 설명 |
|---|---|---|---|
LogBody | IReadOnlyList<ClientLogEvent> | Required | 전송할 로그 이벤트 목록. 기본값은 빈 목록이며, 비어 있어도 요청은 그대로 전송됨. null은 넣지 않음 |
1.2.2.2. ClientLogEvent
| 필드명 | 타입 | 필수 여부 | 설명 |
|---|---|---|---|
EventTime | DateTimeOffset | Required | 이벤트가 발생한 시각. 지정하지 않으면 DateTimeOffset의 기본값이 전송되므로 반드시 지정 |
EventName | string | Required | 앱이 정한 이벤트 이름. 예: levelup_log |
DeviceId | string? | Optional | 기기 식별자. 로그인에 사용하는 DeviceKey와 같은 값을 넣음. 자세한 내용은 DeviceId를 참조하세요. |
UserId | string? | Optional | 사용자 식별자 |
IdentifierProvider | ClientLogEventIdentifierProvider? | Optional | 식별자 제공자. 서버가 항상 hive로 덮어쓰므로 지정하지 않음 |
AdditionalProperties | IDictionary<string, string> | Optional | 앱이 이름을 정한 이벤트 속성. 값은 JSON 값을 나타내는 문자열. 작성 규칙은 이벤트 속성을 참조하세요. |
1.2.3. 호출 예시
AnalyticsCollectClientLogResult의 Success, Failure, UnknownOutcome 결과는 아래 예시와 응답 상태에서 확인합니다. 요청을 수행할 수 없을 때 반환하는 공통 실패(Failure)의 결과 모델과 처리 원칙은 공통 오류 처리를 참조하세요.
아래는 사용자의 레벨이 올랐을 때 로그 이벤트 하나를 만들어 전송하는 예시입니다. 예시의 deviceKey는 앱이 만들어 기기에 저장해 둔 DeviceKey 값을 불러온 변수입니다.
using System;
using System.Collections.Generic;
using Hive.Axyl.Analytics;
using Hive.Axyl.Core;
using UnityEngine;
IAnalyticsService analytics = HiveCore.Resolve<IAnalyticsService>();
var request = new ClientLogCollectRequest
{
LogBody = new[]
{
new ClientLogEvent
{
EventTime = DateTimeOffset.Now, // 이벤트가 발생한 시각
EventName = "levelup_log",
DeviceId = deviceKey, // 로그인에 사용하는 DeviceKey와 같은 값
AdditionalProperties = new Dictionary<string, string>
{
["level"] = "12", // 숫자
["stage"] = "\"boss_room\"", // 문자열은 큰따옴표까지 넣습니다.
["isFirstClear"] = "true", // 불리언
},
},
},
};
AnalyticsCollectClientLogResult result = await analytics.CollectClientLogAsync(request);
switch (result)
{
case AnalyticsCollectClientLogResult.Success:
// 서버가 로그를 수집했습니다. 응답 데이터는 없습니다.
break;
// 공통 실패 처리 (네트워크 오류, 호출 취소, 서버 오류 등)
case AnalyticsCollectClientLogResult.Failure failure:
HiveError err = failure.Problem;
Debug.LogError($"[{err.Code}/{err.ExternalCode}] {err.Message}");
break;
// 이 SDK 버전에서 정의하지 않은 결과는 실패로 처리하고 결과 코드를 기록합니다.
case AnalyticsCollectClientLogResult.UnknownOutcome unknownOutcome:
Debug.LogWarning($"알 수 없는 결과: {unknownOutcome.Code} {unknownOutcome.RawJson}");
break;
default:
Debug.LogWarning($"처리되지 않은 결과: {result.GetType().Name}");
break;
}
1.2.4. 응답 데이터
성공 시 별도 반환 데이터가 없습니다. Success를 받으면 서버가 요청에 담은 로그 이벤트를 수집한 것입니다.
1.2.5. 응답 상태
반환 객체 AnalyticsCollectClientLogResult는 Success, Failure, UnknownOutcome 중 하나입니다. switch 구문으로 분기해 처리하세요.
| 응답 케이스 | 설명 | 앱 클라이언트 대응 |
|---|---|---|
Success | 서버가 로그를 수집했습니다. 응답 데이터는 없습니다. | 추가 처리 없음 |
Failure | 공통 Failure입니다. 네트워크 오류, 호출 취소, 서버 오류 등이 여기에 해당하며, 서버가 보낸 코드는 Failure.Problem.ExternalCode에서 확인합니다. 코드별 의미는 모듈별 공통 Failure 코드를 참조하세요. | 원인별 처리 방법은 실패 원인별 처리를 참조하세요. |
UnknownOutcome | 이 SDK 버전이 알지 못하는 신규 결과입니다. | 실패로 처리하고 결과 코드를 기록 |
2. 서버 전송
Fluentd, HTTP를 통해 앱 서버에서 이벤트 로그를 전송하는 방법입니다.
2.1. Fluentd를 통한 이벤트 로그 전송
앱 서버에서 Fluentd를 통해 직접 이벤트를 전송하는 방법입니다.
- 필수 속성을 포함한 모든 속성을 직접 구성하여 전송해야합니다.
2.1.1. Fluentd 서버 정보
애널리틱스 Fluentd 서버 주소는 다음과 같습니다. 아래 표를 참고하여 이벤트 로그를 전송해야 합니다.
| 구분 | 위치 | 리전 | 도메인 |
|---|---|---|---|
| 상용 | 아시아 | 대한민국(서울) | analytics-hivelog-03.withhive.comanalytics-hivelog-04.withhive.comanalytics-hivelog-05.withhive.comanalytics-hivelog-06.withhive.com |
| 상용 | 아시아 | 싱가포르 | analytics-hivelog-as-sg-01.withhive.comanalytics-hivelog-as-sg-02.withhive.com |
| 상용 | 북미 | 미국(동부) | analytics-hivelog-us-east-01.withhive.comanalytics-hivelog-us-east-02.withhive.com |
| 상용 | 북미 | 미국(서부) | analytics-hivelog-us-west-01.withhive.comanalytics-hivelog-us-west-02.withhive.com |
| 상용 | 유럽 | 프랑크푸르트 | analytics-hivelog-eu-ff-01.withhive.comanalytics-hivelog-eu-ff-02.withhive.com |
| 샌드박스 | 아시아 | 대한민국(서울) | sandbox-analytics-hivelog.withhive.com |
2.1.2. Fluentd 전송 방법
앱 서버에서 JSON 형태의 이벤트 로그를 구성하여 Fluentd를 통해 전송합니다.
fluentd tag 규칙:
전송 JSON 예시:
{
"userId": "100001",
"identifierProvider": "hive",
"deviceId": "100000",
"appId": "com.com2us.game.ios",
"eventTime": "2026-07-20T14:01:01+09:00",
"eventName": "asset_drop",
"level": 10,
"character_name": "AA",
"stage_id": "stage_101"
}
2.1.3. Fluentd 저장 결과
위 예시를 전송하면 BigQuery에 다음과 같이 저장됩니다.
| 컬럼명 | 값 | 수집 방식 |
|---|---|---|
userId | 100001 | 직접 전송 |
identifierProvider | hive | 직접 전송 |
deviceId | 100000 | 직접 전송 |
appId | com.com2us.game.ios | 직접 전송 |
appIdGroup | com.com2us.game | appId 기반 자동 수집 |
dateTime | 2026-07-20T05:01:01Z | eventTime을 UTC로 변환한 값 |
eventName | asset_drop | 직접 전송 |
checksum | b44jskqjwe99921jqe5 | 자동 생성 |
bigqueryRegistTimestamp | 2026-07-20T05:02:01Z | 자동 생성 |
attributes | 아래 참조 | 직접 전송 + 자동 수집 |
attributes 예시
{
"hiveAttributes": {
"dataSource": "custom_server",
"geoIpCountry": "KR"
},
"eventAttributes": {
"eventTime": "2026-07-20T14:01:01+09:00",
"level": 10,
"character_name": "AA",
"stage_id": "stage_101"
}
}
| 영역 | 저장 내용 |
|---|---|
hiveAttributes | 파이프라인 자동 처리 속성 (dataSource, geoIpCountry) |
eventAttributes | 사용자 정의 속성 (level, character_name, stage_id) |
Note
서버 전송(Fluentd)에서는 SDK 자동 수집 속성이 포함되지 않으므로, eventAttributes에는 사용자가 직접 전송한 속성만 저장됩니다.
2.1.4. Fluentd 사용 가이드
Fluentd를 사용하여 다양한 방식으로 이벤트 로그 전송이 가능합니다. 아래 링크를 클릭하여 자세한 내용을 확인하세요.
2.1.5. Fluentd 주의사항 & Tips
- 서버 전송(Fluentd)에서는 SDK 자동 수집 속성이 포함되지 않으므로, 필요한 속성은 모두 직접 구성해서 전송해야 합니다.
- 모든 필수 속성(
userId,identifierProvider,deviceId,appId,appIdGroup,eventTime,eventName)을 반드시 포함해야 합니다.
2.2. HTTP 를 통한 이벤트 로그 전송
HTTP API를 통해 앱 서버 또는 클라이언트에서 직접 이벤트를 전송하는 방법입니다.
- Fluentd 설치가 불가능한 환경에서 서버 이벤트 로그를 전송할 때 적합합니다.
- REST API 형태로 JSON 데이터를 직접 전송합니다.
- 필수 속성을 포함한 모든 속성을 직접 구성하여 전송해야합니다.
2.2.1. 수신 서버 정보
애널리틱스 웹서버 주소는 다음과 같습니다.
| 구분 | URL |
|---|---|
| 상용 | https://analytics-log.withhive.com/v1/server-recv |
| 샌드박스 | https://sandbox-analytics-log.withhive.com/v1/server-recv |
Header 정보:
| 항목 | 값 | 비고 |
|---|---|---|
| Method | POST | |
| Content-Type | application/json; charset=utf8 | 필수 |
| Content-Encoding | gzip | body에 압축 바이너리를 넣을 때 사용 |
2.2.2. HTTP 전송 방법
위 수신 서버 URL로 JSON 데이터를 POST 요청합니다.
HTTP 요청:
요청 Body (JSON):
{
"userId": "100001",
"identifierProvider": "hive",
"deviceId": "100000",
"appId": "com.com2us.game.ios",
"eventTime": "2026-07-20T14:01:01+09:00",
"eventName": "asset_drop",
"level": 10,
"character_name": "AA"
}
2.2.3. HTTP 전송 예시
cURL:
curl -X POST https://analytics-log.withhive.com/v1/server-recv \
-H "Content-Type: application/json" \
-d '{
"userId": "100001",
"identifierProvider": "hive",
"deviceId": "100000",
"appId": "com.com2us.game.ios",
"eventTime": "2026-07-20T14:01:01+09:00",
"eventName": "asset_drop",
"level": 10,
"character_name": "AA"
}'
Python:
import requests
import json
url = "{Analytics 수신 서버 URL}"
data = {
"userId": "100001",
"identifierProvider": "hive",
"deviceId": "100000",
"appId": "com.com2us.game.ios",
"eventTime": "2026-07-20T14:01:01+09:00",
"eventName": "asset_drop",
"level": 10,
"character_name": "AA",
}
response = requests.post(url, json=data)
print(response.status_code)
2.2.4. HTTP 저장 결과
위 예시를 전송하면 BigQuery에 다음과 같이 저장됩니다.
| 컬럼명 | 값 | 수집 방식 |
|---|---|---|
userId | 100001 | 직접 전송 |
identifierProvider | hive | 직접 전송 |
deviceId | 100000 | 직접 전송 |
appId | com.com2us.game.ios | 직접 전송 |
appIdGroup | com.com2us.game | appId 기반 자동 매핑 |
dateTime | 2026-07-20T05:01:01Z | eventTime을 UTC로 변환한 값 |
eventName | asset_drop | 직접 전송 |
checksum | b44jskqjwe99921jqe5 | 자동 생성 |
bigqueryRegistTimestamp | 2026-07-20T05:02:01Z | 자동 생성 |
attributes | 아래 참조 | 직접 전송 + 자동 처리 |
attributes 예시
{
"hiveAttributes": {
"dataSource": "custom_server",
"geoIpCountry": "KR"
},
"eventAttributes": {
"eventTime": "2026-07-20T14:01:01+09:00",
"level": 10,
"character_name": "AA"
}
}
| 영역 | 저장 내용 |
|---|---|
hiveAttributes | 파이프라인 자동 처리 속성 (dataSource, geoIpCountry) |
eventAttributes | 사용자 정의 속성 (level, character_name) |
Note
서버 전송(HTTP)에서는 SDK 자동 수집 속성이 포함되지 않으므로, eventAttributes에는 사용자가 직접 전송한 속성만 저장됩니다.
2.2.5. HTTP 주의사항 & Tips
- 모든 필수 속성(
userId,identifierProvider,deviceId,appId,appIdGroup,eventTime,eventName)을 반드시 포함해야 합니다. Content-Type은application/json으로 설정해야 합니다.- 속성값으로 JSON 객체(
{})나 배열([])을 사용하면 rescue 테이블로 격리됩니다. - 서버 전송(HTTP)에서는 SDK 자동 수집 속성이 포함되지 않으므로, 필요한 속성은 모두 직접 구성해서 전송해야 합니다.
3. 더 알아보기
- 이벤트 속성 전송 — 필수/자동 수집/사용자 정의 속성 상세 규칙
- 이벤트 저장 구조 > 테이블 구조 — BigQuery 저장 구조
- 이벤트 저장 구조 > 데이터 격리 — rescue 테이블 격리 사유와 조회 방법