Send event logs
Overview
You can send event logs to Analytics. When you configure the events to send, check the event structures provided in Event template and whether Hive Axyl collects each event automatically.
You can send event logs that need additional analysis from the client or the server.
1. Send from the client with Hive Axyl
This method sends event logs from the client through Hive Axyl. Call CollectClientLogAsync() to send events that occur in the app to Analytics. Before you call it, create a log event for each event and put them in a single list. For the full API, see IAnalyticsService.
1.1. Prepare log events
A log event is data that records a single event that occurred in the app, and it is the unit that Analytics collects and analyzes. A single log event contains an event name, an event time, and attributes that the app defines.
Create log events as ClientLogEvent objects and put them in the LogBody list of ClientLogCollectRequest. All log events in the list are sent in a single request. Even if LogBody is empty, the SDK sends the request as is, so include at least one log event when you call it. Prepare each field of ClientLogEvent as follows.
1.1.1. EventName
In EventName, put the event name as a string that indicates which event occurred. This value is required for every log event. The app defines the name. For example, for a log event you send when the user's level goes up, use a name such as levelup_log.
1.1.2. EventTime
In EventTime, put the time when the event occurred as a DateTimeOffset value. This value is required for every log event. Get the current time with DateTimeOffset.Now when the event occurs and put it in. Even if you collect log events and send them later, you must put the event time, not the sending time.
The SDK converts EventTime into an RFC 3339 string, the internet standard format for dates and times, and sends it. This string also includes the offset from Coordinated Universal Time (UTC). If you do not specify EventTime, the SDK does not treat it as an error and sends the default value of DateTimeOffset as is, so you must specify it yourself. The following are examples of the string sent for each EventTime value.
- 7:34:42 AM on January 1, 2026, Korea time:
2026-01-01T07:34:42.0000000+09:00 - When not specified:
0001-01-01T00:00:00.0000000+00:00
1.1.3. DeviceId
In DeviceId, you must put exactly the same value as the DeviceKey that the app puts in login requests. This is because data can be analyzed accurately only when the device that sent the log event matches the device used for authentication.
DeviceKey is the device identification value that goes into login requests regardless of the account type, such as guest, username, external authentication provider, or custom account. The SDK does not fill in DeviceId automatically and does not save DeviceKey. Have the app put in the value itself in the following order.
- Load the
DeviceKeythat the app created and saved on the device.DeviceKeyis a value created and saved once when the app is first launched, so it is already on the device even before login. For how to create and store it, see deviceKey. - Put the loaded value in
DeviceIdas is. Put the same value in every log event, both before and after login, and do not create a new value forDeviceId.
1.1.4. UserId
UserId is an optional field that holds the user identifier. If you do not set it, the log event is sent without this field.
1.1.5. IdentifierProvider
IdentifierProvider is an optional field that indicates the identifier provider. The server always overwrites it with hive, so do not specify it.
1.1.6. Event attributes
Add information needed for analysis other than the event name and event time to AdditionalProperties as event attributes. The server collects the attributes without interpreting their contents, so you do not need to define attributes in advance. The app decides their names and number and sends them.
AdditionalProperties is a dictionary that holds attribute names as keys and attribute values as values. The SDK builds the request body in JSON, a data interchange format, and sends it. Each attribute is recorded as a field at the same level as the event name. The default value is an empty dictionary, and if it is empty, no attributes are sent.
1.1.6.1. Attribute value format
For attribute values, put the JSON value itself as a string, not text to display on screen. For example, a string value must include its double quotes.
| Value type | Value in C# code | JSON sent |
|---|---|---|
| Number | "42" | 42 |
| String | "\"gold\"" | "gold" |
| Boolean | "true" | true |
| Array | "[1,2]" | [1,2] |
| Object | "{\"a\":1}" | {"a":1} |
| JSON null | "null" | null |
| C# null | null | null |
Warning
The SDK does not validate attribute values and writes them to the request body as is. If even one value is not a valid JSON value, such as putting the string value gold as "gold" instead of "\"gold\"", the entire request body becomes invalid JSON. Other log events in the same request are also sent in the invalid body.
1.1.6.2. Attribute names to avoid
eventTime, eventName, deviceId, userId, and identifierProvider are the names used to send the fields of ClientLogEvent. If you use these names as attribute names, a field with the same name can be sent twice in one log event, so do not use them.
1.2. Send event logs
Call CollectClientLogAsync() to send the prepared list of log events. When the server collects the logs, it returns Success, and there is no response data. The SDK automatically sends the App ID you specified during initialization with every request, so you do not need to put it in the request.
1.2.1. Send before and after login
Call CollectClientLogAsync() the same way both before and after the user logs in. Login is not a requirement for using Analytics, so events that occur before login, such as right after the app launches, are also sent. The only thing that differs depending on login status is the authentication information that the SDK includes in the request.
- Before login: The request is sent without an authentication token
- After the login session is activated: The session's authentication token is automatically included in the request
When a login session is active, the server identifies the user who sent the logs from the authentication token in the request. The SDK adds the authentication token, so the app does not need to put it in the request itself.
1.2.2. Call parameters
| Field name | Type | Required | Description |
|---|---|---|---|
request | ClientLogCollectRequest | Required | The request that holds the list of log events to send |
context | ApiCallContext? | Optional | Per-call settings object. If omitted, the default values are used. |
If you pass null to request, an ArgumentNullException is thrown.
1.2.2.1. ClientLogCollectRequest
| Field name | Type | Required | Description |
|---|---|---|---|
LogBody | IReadOnlyList<ClientLogEvent> | Required | List of log events to send. The default value is an empty list, and the request is sent as is even if it is empty. Do not put null |
1.2.2.2. ClientLogEvent
| Field name | Type | Required | Description |
|---|---|---|---|
EventTime | DateTimeOffset | Required | Time when the event occurred. If not specified, the default value of DateTimeOffset is sent, so always specify it |
EventName | string | Required | Event name that the app defines. Example: levelup_log |
DeviceId | string? | Optional | Device identifier. Put the same value as the DeviceKey used for login. For details, see DeviceId. |
UserId | string? | Optional | User identifier |
IdentifierProvider | ClientLogEventIdentifierProvider? | Optional | Identifier provider. The server always overwrites it with hive, so do not specify it |
AdditionalProperties | IDictionary<string, string> | Optional | Event attributes whose names the app defines. Values are strings that represent JSON values. For the rules, see Event attributes. |
1.2.3. Call example
Check the Success, Failure, and UnknownOutcome results of AnalyticsCollectClientLogResult in the following example and in the response status. For the result model and handling principles of the common failure (Failure) returned when the request cannot be performed, see Common error handling.
The following example creates and sends one log event when the user's level goes up. In the example, deviceKey is a variable that holds the DeviceKey value the app created and saved on the device.
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, // Time when the event occurred
EventName = "levelup_log",
DeviceId = deviceKey, // Same value as the DeviceKey used for login
AdditionalProperties = new Dictionary<string, string>
{
["level"] = "12", // Number
["stage"] = "\"boss_room\"", // For strings, include the double quotes.
["isFirstClear"] = "true", // Boolean
},
},
},
};
AnalyticsCollectClientLogResult result = await analytics.CollectClientLogAsync(request);
switch (result)
{
case AnalyticsCollectClientLogResult.Success:
// The server collected the logs. There is no response data.
break;
// Handle common failures (network errors, call cancellation, server errors, and so on)
case AnalyticsCollectClientLogResult.Failure failure:
HiveError err = failure.Problem;
Debug.LogError($"[{err.Code}/{err.ExternalCode}] {err.Message}");
break;
// Treat results that this SDK version does not define as failures and record the result code.
case AnalyticsCollectClientLogResult.UnknownOutcome unknownOutcome:
Debug.LogWarning($"Unknown result: {unknownOutcome.Code} {unknownOutcome.RawJson}");
break;
default:
Debug.LogWarning($"Unhandled result: {result.GetType().Name}");
break;
}
1.2.4. Response data
No data is returned on success. When you receive Success, the server has collected the log events in the request.
1.2.5. Response status
The returned object AnalyticsCollectClientLogResult is one of Success, Failure, or UnknownOutcome. Branch with a switch statement to handle it.
| Response case | Description | App client handling |
|---|---|---|
Success | The server collected the logs. There is no response data. | No further handling |
Failure | Common Failure. This includes network errors, call cancellation, server errors, and so on, and you can check the code the server sent in Failure.Problem.ExternalCode. For the meaning of each code, see Common Failure codes by module. | For how to handle each cause, see Handling by failure cause. |
UnknownOutcome | A new result that this SDK version does not recognize. | Treat it as a failure and record the result code |
2. Send from the server
These methods send event logs from the app server through Fluentd or HTTP.
2.1. Send event logs through Fluentd
This method sends events directly from the app server through Fluentd.
- You must build and send all attributes yourself, including the required attributes.
2.1.1. Fluentd server information
The Analytics Fluentd server addresses are as follows. Send event logs by referring to the following table.
| Category | Location | Region | Domain |
|---|---|---|---|
| Production | Asia | South Korea (Seoul) | analytics-hivelog-03.withhive.comanalytics-hivelog-04.withhive.comanalytics-hivelog-05.withhive.comanalytics-hivelog-06.withhive.com |
| Production | Asia | Singapore | analytics-hivelog-as-sg-01.withhive.comanalytics-hivelog-as-sg-02.withhive.com |
| Production | North America | United States (East) | analytics-hivelog-us-east-01.withhive.comanalytics-hivelog-us-east-02.withhive.com |
| Production | North America | United States (West) | analytics-hivelog-us-west-01.withhive.comanalytics-hivelog-us-west-02.withhive.com |
| Production | Europe | Frankfurt | analytics-hivelog-eu-ff-01.withhive.comanalytics-hivelog-eu-ff-02.withhive.com |
| Sandbox | Asia | South Korea (Seoul) | sandbox-analytics-hivelog.withhive.com |
2.1.2. How to send with Fluentd
Build event logs in JSON format on the app server and send them through Fluentd.
fluentd tag rule:
Example JSON to send:
{
"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 storage results
When you send the example above, it is stored in BigQuery as follows.
| Column name | Value | Collection method |
|---|---|---|
userId | 100001 | Sent directly |
identifierProvider | hive | Sent directly |
deviceId | 100000 | Sent directly |
appId | com.com2us.game.ios | Sent directly |
appIdGroup | com.com2us.game | Automatically collected based on appId |
dateTime | 2026-07-20T05:01:01Z | eventTime converted to UTC |
eventName | asset_drop | Sent directly |
checksum | b44jskqjwe99921jqe5 | Automatically generated |
bigqueryRegistTimestamp | 2026-07-20T05:02:01Z | Automatically generated |
attributes | See below | Sent directly + automatically collected |
attributes example
{
"hiveAttributes": {
"dataSource": "custom_server",
"geoIpCountry": "KR"
},
"eventAttributes": {
"eventTime": "2026-07-20T14:01:01+09:00",
"level": 10,
"character_name": "AA",
"stage_id": "stage_101"
}
}
| Area | Stored content |
|---|---|
hiveAttributes | Attributes processed automatically by the pipeline (dataSource, geoIpCountry) |
eventAttributes | Custom attributes (level, character_name, stage_id) |
Note
Server sending (Fluentd) does not include the attributes the SDK collects automatically, so eventAttributes stores only the attributes you sent directly.
2.1.4. Fluentd usage guide
You can send event logs in various ways with Fluentd. Click the following links for details.
- Fluentd usage guide
- Send event logs with an application library
- Send event logs by reading a specific log file
2.1.5. Fluentd notes & tips
- Server sending (Fluentd) does not include the attributes the SDK collects automatically, so you must build and send all the attributes you need yourself.
- You must include all required attributes (
userId,identifierProvider,deviceId,appId,appIdGroup,eventTime,eventName).
2.2. Send event logs through HTTP
This method sends events directly from the app server or client through the HTTP API.
- It is suitable for sending server event logs in environments where you cannot install Fluentd.
- You send JSON data directly in the form of a REST API.
- You must build and send all attributes yourself, including the required attributes.
2.2.1. Receiving server information
The Analytics web server addresses are as follows.
| Category | URL |
|---|---|
| Production | https://analytics-log.withhive.com/v1/server-recv |
| Sandbox | https://sandbox-analytics-log.withhive.com/v1/server-recv |
Header information:
| Item | Value | Remarks |
|---|---|---|
| Method | POST | |
| Content-Type | application/json; charset=utf8 | Required |
| Content-Encoding | gzip | Used when you put compressed binary data in the body |
2.2.2. How to send with HTTP
Send the JSON data in a POST request to the receiving server URL above.
HTTP request:
Request 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 sending examples
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 receiving server 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 storage results
When you send the example above, it is stored in BigQuery as follows.
| Column name | Value | Collection method |
|---|---|---|
userId | 100001 | Sent directly |
identifierProvider | hive | Sent directly |
deviceId | 100000 | Sent directly |
appId | com.com2us.game.ios | Sent directly |
appIdGroup | com.com2us.game | Automatically mapped based on appId |
dateTime | 2026-07-20T05:01:01Z | eventTime converted to UTC |
eventName | asset_drop | Sent directly |
checksum | b44jskqjwe99921jqe5 | Automatically generated |
bigqueryRegistTimestamp | 2026-07-20T05:02:01Z | Automatically generated |
attributes | See below | Sent directly + automatically processed |
attributes example
{
"hiveAttributes": {
"dataSource": "custom_server",
"geoIpCountry": "KR"
},
"eventAttributes": {
"eventTime": "2026-07-20T14:01:01+09:00",
"level": 10,
"character_name": "AA"
}
}
| Area | Stored content |
|---|---|
hiveAttributes | Attributes processed automatically by the pipeline (dataSource, geoIpCountry) |
eventAttributes | Custom attributes (level, character_name) |
Note
Server sending (HTTP) does not include the attributes the SDK collects automatically, so eventAttributes stores only the attributes you sent directly.
2.2.5. HTTP notes & tips
- You must include all required attributes (
userId,identifierProvider,deviceId,appId,appIdGroup,eventTime,eventName). - You must set
Content-Typetoapplication/json. - If you use a JSON object (
{}) or an array ([]) as an attribute value, the data is isolated in the rescue table. - Server sending (HTTP) does not include the attributes the SDK collects automatically, so you must build and send all the attributes you need yourself.
3. Learn more
- Send event attributes — Detailed rules for required, automatically collected, and custom attributes
- Event storage structure > Table structure — BigQuery storage structure
- Event storage structure > Data isolation — Reasons for rescue table isolation and how to query it