All Products
Search
Document Center

ApsaraVideo VOD:Log system

Last Updated:Sep 10, 2026

The Log System is a fundamental module of AliPlayerKit. It uses a unified log center, LogHub, to provide core features such as log output, level filtering, and an observer mechanism. This provides visibility and traceability for player runtime information.

Concepts

What is LogHub?

LogHub is the unified entry point for all log output in AliPlayerKit. It is designed with the singleton pattern. LogHub encapsulates the native iOS log API, NSLog, and adds the following core features:

Capabilities

Description

Log switch

Controls whether log output is enabled (master switch).

Console switch

Controls whether logs are output to the Xcode Console.

Level filtering

Outputs only logs of a specified level or higher.

Observer mechanism

Lets external observers receive log output for custom processing, such as writing to a file.

What is a log observer?

A log observer (LogObserver) is a callback protocol used to receive logs from LogHub. By implementing this protocol, you can customize how logs are processed. For example:

  • Write logs to a file for the technical support team to use for troubleshooting.

  • Upload logs to a remote server to enable remote log collection.

  • Display logs in the UI to create a debug panel.

Hybrid thread model

LogHub uses a hybrid thread model:

Operation

Thread

Thread name and timestamp capture

Synchronous execution in the calling thread

Console output (NSLog)

Synchronous execution in the calling thread

Observer notification

Asynchronous dispatch to a background serial queue

Note

The LogObserver.onLog: callback is executed in a background serial queue. You must switch to the main thread to update the UI.

Features

Core features

Capabilities

Description

Multi-level logging

Supports five levels: Verbose, Debug, Info, Warn, and Error.

Triple control

Global switch, level filtering, and console switch for precise control over the output scope.

Observer mechanism

Lets you register custom observers for log persistence, remote reporting, and more.

Helper macros

Provides SLOGV/D/I/W/E macros that automatically capture the source code location.

Log panel

Displays logs in real time within the player view using LogPanelSlot (for debugging only).

Global shortcut API

Quickly configure log levels and console output using AliPlayerKit class methods.

Core components

Component

Type

Description

LogHub

Singleton

Log center, the unified entry point for log output.

LogLevel

Enumeration

Log level definition.

LogInfo

Data class

Log information model that encapsulates the complete information of a single log entry.

LogObserver

Protocol

Log observer interface.

LogPanelSlot

Slot

An embedded log panel in the player that displays key logs in real time.

Usage

Basic usage: Global quick configuration

You can quickly configure the log system using the recommended AliPlayerKit class methods:

// In AppDelegate, configure after setup
[AliPlayerKit setup];

// Set the log level
[AliPlayerKit setLogLevel:LogLevelVerbose];

// Enable or disable console logs
[AliPlayerKit enableConsoleLog:YES];

AliPlayerKit method

Description

setLogLevel:

Sets the log level. Logs below this level are ignored. The default is LogLevelInfo.

logLevel

Gets the current log level.

enableConsoleLog:

Enables or disables console output. Enabled by default.

isConsoleLogEnabled

Checks if console logging is enabled.

setDebugModeEnabled:

Enables or disables debug mode.

isDebugModeEnabled

Checks if debug mode is enabled.

setLogPanelEnabled:

Enables or disables the log panel slot. Disabled by default.

isLogPanelEnabled

Checks if the log panel is enabled.

Basic usage: Log output

You can use the SLOG series of helper macros to output logs at different levels. These macros automatically capture the source file name and line number:

#import <AliPlayerKit/LogMacros.h>

// Output logs at different levels (automatically captures __FILE_NAME__ and __LINE__)
SLOGV(@"viewDidLoad called");
SLOGD(@"Configure player: videoId=%@", videoId);
SLOGI(@"Start playing video: %@", videoTitle);
SLOGW(@"Buffering, current progress: %.1f%%", progress * 100);
SLOGE(@"Playback failed, error code: %ld", (long)errorCode);

List of helper macros:

Macro

Level

Description

SLOGV(fmt, ...)

Verbose

Most detailed log level.

SLOGD(fmt, ...)

Debug

Debug information.

SLOGI(fmt, ...)

Info

General information.

SLOGW(fmt, ...)

Warn

Potential issues.

SLOGE(fmt, ...)

Error

Error messages.

Note

The SLOG macros call the LogHub logLevel:file:line:message:error: method. They automatically capture the source code location using __FILE_NAME__ and __LINE__, so you do not need to manually pass a tag.

You can also call LogHub instance methods directly and specify a tag manually:

// Use a tag to identify the log source
[[LogHub sharedHub] i:@"PlayerVC" msg:@"Start playback"];
[[LogHub sharedHub] e:@"MediaPlayer" msg:@"Playback failed" error:error];

Basic usage: Configure log levels

You can configure log properties directly through LogHub:

LogHub *logHub = [LogHub sharedHub];

#ifdef DEBUG
    // Development environment: Verbose logs + console output
    logHub.logEnabled = YES;
    logHub.consoleLogEnabled = YES;
    logHub.logLevel = LogLevelVerbose;
#else
    // Production environment: Concise logs + console disabled
    logHub.logEnabled = YES;
    logHub.consoleLogEnabled = NO;
    logHub.logLevel = LogLevelInfo;
#endif

Triple control mechanism:

Control layer

Property

Description

Master switch

logEnabled

When disabled, all logging is silenced, including observer notifications.

Level filtering

logLevel

Logs below this level are ignored. The default is LogLevelInfo.

Console switch

consoleLogEnabled

Controls whether logs are output to the Xcode Console using NSLog.

Note

If you disable consoleLogEnabled, logs are still dispatched through observer notifications, but the console output is suppressed. If you disable logEnabled, all log requests are ignored, and observers do not receive notifications.

Advanced usage: Register a log observer

You can customize log processing by implementing the LogObserver protocol:

// Create and register a file log observer
FileLogObserver *fileObserver = [[FileLogObserver alloc] init];
[[LogHub sharedHub] addObserver:fileObserver];

// Remove the observer when it is no longer needed
[[LogHub sharedHub] removeObserver:fileObserver];
Note

LogHub maintains a strong reference to observers until they are explicitly removed using removeObserver:. You must call removeObserver: at an appropriate time, such as in dealloc or viewWillDisappear:, to prevent circular references.

Advanced usage: Log panel

LogPanelSlot is a built-in debug slot that displays key log information in real time within the player view:

// Enable the log panel (recommended only for debugging scenarios)
[AliPlayerKit setLogPanelEnabled:YES];

Interaction

Description

Click the title bar

Expands or collapses the log content area.

Click the "Clear" button

Clears the displayed logs.

Long-press the log area

Copies the log content to the clipboard.

Note

The log panel displays only logs with a level of Debug or higher. You must call setLogPanelEnabled: before you call rebuildSlots. The panel is not visible in the Minimal scenario.

Custom development

LogObserver protocol

@protocol LogObserver <NSObject>

@required

/// Log output callback
/// @param logInfo The log information object, which contains the level, tag, message, and timestamp.
/// @warning This callback is executed in a background serial queue. Dispatch to the main thread to update the UI.
- (void)onLog:(LogInfo *)logInfo;

@end

LogInfo data model

Property

Type

Description

level

LogLevel

Log level (readonly).

tag

NSString *

Log tag (readonly).

message

NSString *

Log message content (readonly).

timestamp

NSDate *

Timestamp when the log was generated (readonly).

threadName

NSString *

Name of the thread that generated the log (readonly).

fileName

NSString *

Source file name, such as @"MyClass.m" (readonly).

line

NSInteger

Source code line number (readonly).

error

NSError *

Associated error object, which can be nil (readonly).

Method

Description

formattedString

Gets the formatted log string.

initWithLevel:fileName:line:message:error:threadName:timestamp:

Designated initializer.

initWithLevel:tag:message:

Convenience initializer that automatically captures the timestamp and thread name.

Formatted output format:

2024-04-22 10:30:00.123 I/AliPlayerKit [version] [FileName:line] [threadName] : message

If an error exists, an extra line is appended:

Error: domain=xxx code=xxx userInfo=xxx

Example: Custom file log observer

The following is a complete implementation of a file log observer:

@interface MyFileLogObserver : NSObject <LogObserver>
- (instancetype)initWithLogDirectory:(NSString *)directory;
@end

@implementation MyFileLogObserver {
    NSString *_logFilePath;
    dispatch_queue_t _writeQueue;
    NSFileHandle *_fileHandle;
}

- (instancetype)initWithLogDirectory:(NSString *)directory {
    self = [super init];
    if (self) {
        _writeQueue = dispatch_queue_create("com.example.filelog",
                                            DISPATCH_QUEUE_SERIAL);
        [self setupLogFileAtDirectory:directory];
    }
    return self;
}

- (void)setupLogFileAtDirectory:(NSString *)directory {
    NSFileManager *fm = [NSFileManager defaultManager];
    if (![fm fileExistsAtPath:directory]) {
        [fm createDirectoryAtPath:directory
      withIntermediateDirectories:YES
                       attributes:nil
                            error:nil];
    }

    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    formatter.dateFormat = @"yyyy-MM-dd";
    NSString *fileName = [NSString stringWithFormat:@"player_%@.log",
                          [formatter stringFromDate:[NSDate date]]];
    _logFilePath = [directory stringByAppendingPathComponent:fileName];

    if (![fm fileExistsAtPath:_logFilePath]) {
        [fm createFileAtPath:_logFilePath contents:nil attributes:nil];
    }
    _fileHandle = [NSFileHandle fileHandleForWritingAtPath:_logFilePath];
    [_fileHandle seekToEndOfFile];
}

#pragma mark - LogObserver

- (void)onLog:(LogInfo *)logInfo {
    NSString *formatted = [logInfo formattedString];

    dispatch_async(_writeQueue, ^{
        NSString *line = [formatted stringByAppendingString:@"\n"];
        NSData *data = [line dataUsingEncoding:NSUTF8StringEncoding];
        @try {
            [self->_fileHandle writeData:data];
        } @catch (NSException *exception) {
            // Ignore write exceptions
        }
    });
}

- (void)dealloc {
    [_fileHandle closeFile];
}

@end
Note

The onLog: callback is executed in a background serial queue. However, for file I/O operations, we recommend that you use a separate write queue to prevent blocking the log dispatch queue. Blocking the queue could affect other observers.

Example: Full integration

// AppDelegate.m
#import <AliPlayerKit/AliPlayerKit.h>

@interface AppDelegate ()
@property (nonatomic, strong) MyFileLogObserver *fileLogObserver;
@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    // 1. Initialize AliPlayerKit
    [AliPlayerKit setup];

    // 2. Configure the log system
#ifdef DEBUG
    [AliPlayerKit setLogLevel:LogLevelVerbose];
    [AliPlayerKit enableConsoleLog:YES];
    // Optional: Enable the log panel
    [AliPlayerKit setLogPanelEnabled:YES];
#else
    [AliPlayerKit setLogLevel:LogLevelInfo];
    [AliPlayerKit enableConsoleLog:NO];

    // 3. Register a file log observer (production environment only)
    NSString *logDir = [NSSearchPathForDirectoriesInDomains(
        NSDocumentDirectory, NSUserDomainMask, YES).firstObject
        stringByAppendingPathComponent:@"PlayerLogs"];
    self.fileLogObserver = [[MyFileLogObserver alloc] initWithLogDirectory:logDir];
    [[LogHub sharedHub] addObserver:self.fileLogObserver];
#endif

    return YES;
}

@end
Note

The PlayerKitUsages/UsageLogSystem module provides a complete example of how to use the log system. The example includes a FileLogObserver and a UI for displaying logs.

Best practices

Environment configuration recommendations

Environment

Master Switch

Console

Level

Observer

Log Panel

Development and debugging

YES

YES

Verbose

Optional (UI panel)

Optional

Internal testing

YES

YES

Debug

File logging

NO

Production environment

YES

NO

Info

File logging + remote reporting

NO

Sensitive scenarios

NO

—

—

—

NO

Common errors

Error 1: Updating the UI directly in the observer callback

// ✗ Incorrect: onLog: is executed in a background serial queue. Updating the UI directly will cause a crash.
- (void)onLog:(LogInfo *)logInfo {
    self.logLabel.text = [logInfo formattedString];  // Crash!
}

// ✓ Correct: Switch to the main thread to update the UI.
- (void)onLog:(LogInfo *)logInfo {
    NSString *formatted = [logInfo formattedString];
    dispatch_async(dispatch_get_main_queue(), ^{
        self.logLabel.text = formatted;
    });
}

Error 2: Synchronous blocking operations in the observer

// ✗ Incorrect: Synchronously writing to a file in the callback blocks the log dispatch queue.
- (void)onLog:(LogInfo *)logInfo {
    NSString *log = [logInfo formattedString];
    [log writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:nil];
}

// ✓ Correct: Asynchronously write to the file.
- (void)onLog:(LogInfo *)logInfo {
    NSString *log = [logInfo formattedString];
    dispatch_async(_writeQueue, ^{
        // Asynchronous write...
    });
}

Error 3: Forgetting to remove the observer, which causes a circular reference

// ✗ Incorrect: LogHub strongly references the observer. Failure to remove it causes a circular reference.
- (void)viewDidLoad {
    [[LogHub sharedHub] addObserver:self];
    // Never released...
}

// ✓ Correct: Remove the observer at the end of the lifecycle.
- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [[LogHub sharedHub] removeObserver:self];
}
Note

Unlike the notification system's Dispatcher, LogHub maintains a strong reference to observers. If you do not call removeObserver:, the observer is not released.

API reference

Log levels (LogLevel)

Level

Enumeration value

Numeric value

Description

Verbose

LogLevelVerbose

0

Most detailed, for development and debugging.

Debug

LogLevelDebug

1

Debug information.

Info

LogLevelInfo

2

Default level, recommended for production.

Warn

LogLevelWarn

3

Potential issues.

Error

LogLevelError

4

Error messages.

None

LogLevelNone

100

Disables all logs.

Note

LogLevel.h also provides the LogLevelToString() inline function, which converts a log level to an abbreviated string (V, D, I, W, E, or N).

LogHub core API

Property / Method

Type

Description

+sharedHub

Class method

Gets the singleton instance.

logEnabled

BOOL

Master log switch (default: YES).

logLevel

LogLevel

Log level (default: LogLevelInfo).

consoleLogEnabled

BOOL

Console switch (default: YES).

v:msg:

Instance method

Outputs a Verbose log.

d:msg:

Instance method

Outputs a Debug log.

i:msg:

Instance method

Outputs an Info log.

w:msg:

Instance method

Outputs a Warn log.

e:msg:

Instance method

Outputs an Error log.

e:msg:error:

Instance method

Outputs an Error log with an NSError.

log:tag:msg:

Instance method

Outputs a log at the specified level.

logLevel:file:line:message:error:

Instance method

Core logging method (used by SLOG macros).

addObserver:

Instance method

Adds an observer (strong reference, no effect if added repeatedly).

removeObserver:

Instance method

Removes an observer.

+levelToString:

Class method

Converts a level to a string (V/D/I/W/E/N).

+stringToLevel:

Class method

Converts a string to a level (case-insensitive, returns LogLevelInfo if unrecognized).

AliPlayerKit log shortcut API

Method

Description

+setLogLevel:

Sets the log level (must be called after setup).

+logLevel

Gets the current log level.

+enableConsoleLog:

Enables or disables console log output.

+isConsoleLogEnabled

Checks if console logging is enabled.

+setDebugModeEnabled:

Enables or disables debug mode.

+isDebugModeEnabled

Checks if debug mode is enabled.

+setLogPanelEnabled:

Enables or disables the log panel slot.

+isLogPanelEnabled

Checks if the log panel is enabled.

SLOG helper macros

Macro

Level

Expanded form

SLOGV(fmt, ...)

Verbose

[[LogHub sharedHub] logLevel:LogLevelVerbose file:@(__FILE_NAME__) line:__LINE__ message:... error:nil]

SLOGD(fmt, ...)

Debug

Same as above, with level Debug.

SLOGI(fmt, ...)

Info

Same as above, with level Info.

SLOGW(fmt, ...)

Warn

Same as above, with level Warn.

SLOGE(fmt, ...)

Error

Same as above, with level Error.

LogInfo properties

Property

Type

Description

level

LogLevel

Log level.

tag

NSString *

Log tag.

message

NSString *

Log message content.

timestamp

NSDate *

Timestamp when the log was generated.

threadName

NSString *

Thread name.

fileName

NSString *

Source file name.

line

NSInteger

Source code line number.

error

NSError *

Associated error object (nullable).

formattedString

Method

Gets the formatted log string.

LogObserver protocol

Method

Required

Description

onLog:

Yes (@required)

Log output callback, executed in a background serial queue.