Todos os produtos
Search
Central de documentação

ApsaraVideo VOD:Sistema de logs

Última atualização: Sep 11, 2026

O sistema de logs é um módulo fundamental do AliPlayerKit. Ele utiliza um centro de logs unificado, o LogHub, para oferecer recursos essenciais como saída de logs, filtragem por nível e mecanismo de observer. Isso garante visibilidade e rastreabilidade das informações de execução do player.

Conceitos

O que é o LogHub?

O LogHub é o ponto de entrada unificado para toda a saída de logs no AliPlayerKit. Seu design segue o padrão singleton. O LogHub encapsula a API nativa de logs do iOS, NSLog, e adiciona os seguintes recursos principais:

Capacidades

Descrição

Chave geral de logs

Controla se a saída de logs está ativada (chave mestra).

Chave do console

Define se os logs são enviados ao Xcode console.

Filtragem por nível

Emite apenas logs de um nível especificado ou superior.

Mecanismo de observer

Permite que observers externos recebam a saída de logs para processamento personalizado, como gravação em arquivo.

O que é um log observer?

Um log observer (LogObserver) é um protocolo de callback usado para receber logs do LogHub. Ao implementar esse protocolo, você personaliza o processamento dos logs. Por exemplo:

  • Grave logs em arquivo para que a equipe de suporte técnico os utilize na resolução de problemas.

  • Envie logs a um servidor remoto para viabilizar a coleta remota.

  • Exiba logs na interface para criar um painel de depuração.

Modelo híbrido de threads

O LogHub adota um modelo híbrido de threads:

Operação

Thread

Captura do nome da thread e timestamp

Execução síncrona na thread chamadora

Saída no console (NSLog)

Execução síncrona na thread chamadora

Notificação de observers

Despacho assíncrono para uma fila serial em background

Nota

O callback LogObserver.onLog: é executado em uma fila serial em background. Para atualizar a interface, mude para a main thread.

Recursos

Recursos principais

Capacidades

Descrição

Logs multinível

Suporta cinco níveis: Verbose, Debug, Info, Warn e Error.

Controle triplo

Combina chave global, filtragem por nível e chave do console para controlar com precisão o escopo de saída.

Mecanismo de observer

Permite registrar observers personalizados para persistência de logs, relatórios remotos, entre outros.

Macros auxiliares

Oferece as macros SLOGV/D/I/W/E, que capturam automaticamente a localização no source.

Painel de logs

Exibe logs em tempo real dentro da visualização do player por meio do LogPanelSlot (apenas para depuração).

API de atalho global

Configure rapidamente níveis de log e saída no console usando métodos de classe do AliPlayerKit.

Componentes principais

Componente

Tipo

Descrição

LogHub

Singleton

Centro de logs; ponto de entrada unificado para saída de logs.

LogLevel

Enumeração

Definição dos níveis de log.

LogInfo

Classe de dados

Modelo de informações de log que encapsula todos os dados de uma única entrada.

LogObserver

Protocolo

Interface do log observer.

LogPanelSlot

Slot

Painel de logs embutido no player que exibe logs importantes em tempo real.

Uso

Uso básico: configuração rápida global

Configure rapidamente o sistema de logs usando os métodos de classe recomendados do AliPlayerKit:

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

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

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

Método do AliPlayerKit

Descrição

setLogLevel:

Defina o nível de log. Logs abaixo desse nível são ignorados. O padrão é LogLevelInfo.

logLevel

Obtém o nível de log atual.

enableConsoleLog:

Ative ou desative a saída no console. Ativado por padrão.

isConsoleLogEnabled

Verifica se o log no console está ativado.

setDebugModeEnabled:

Ative ou desative o modo de depuração.

isDebugModeEnabled

Verifica se o modo de depuração está ativado.

setLogPanelEnabled:

Ative ou desative o slot do painel de logs. Desativado por padrão.

isLogPanelEnabled

Verifica se o painel de logs está ativado.

Uso básico: saída de logs

Use a família de macros auxiliares SLOG para emitir logs em diferentes níveis. Essas macros capturam automaticamente o nome do arquivo de origem e o número da linha:

#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);

Lista de macros auxiliares:

Macro

Nível

Descrição

SLOGV(fmt, ...)

Verbose

Nível de log mais detalhado.

SLOGD(fmt, ...)

Debug

Informações de depuração.

SLOGI(fmt, ...)

Info

Informações gerais.

SLOGW(fmt, ...)

Warn

Problemas potenciais.

SLOGE(fmt, ...)

Error

Mensagens de erro.

Nota

As macros SLOG chamam o método logLevel:file:line:message:error: do LogHub. Elas capturam automaticamente a localização no source usando __FILE_NAME__ e __LINE__, eliminando a necessidade de passar uma tag manualmente.

Também é possível chamar diretamente os métodos de instância do LogHub e especifique uma tag manualmente:

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

Uso básico: configuração de níveis de log

Configure as propriedades de log diretamente pelo 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

Mecanismo de controle triplo:

Camada de controle

Propriedade

Descrição

Chave mestra

logEnabled

Quando desativada, silencia todos os logs, inclusive as notificações aos observers.

Filtragem por nível

logLevel

Logs abaixo desse nível são ignorados. O padrão é LogLevelInfo.

Chave do console

consoleLogEnabled

Controla se os logs são enviados ao Xcode console via NSLog.

Nota

Ao desativar consoleLogEnabled, os logs continuam sendo despachados pelas notificações dos observers, mas a saída no console é suprimida. Se você desativar logEnabled, todas as solicitações de log serão ignoradas e os observers não receberão notificações.

Uso avançado: registro de um log observer

Personalize o processamento de logs implementando o protocolo LogObserver:

// 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];
Nota

O LogHub mantém uma referência forte aos observers até que sejam removidos explicitamente com removeObserver:. Chame removeObserver: no momento adequado, como em dealloc ou viewWillDisappear:, para evitar referências circulares.

Uso avançado: painel de logs

O LogPanelSlot é um slot de depuração integrado que exibe informações importantes de log em tempo real na visualização do player:

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

Interação

Descrição

Clique em na barra de título

Expande ou recolhe a área de conteúdo dos logs.

Clique em no botão "Clear"

Limpa os logs exibidos.

Toque longo na área de logs

Copia o conteúdo dos logs para a área de transferência.

Nota

O painel de logs exibe apenas logs com nível Debug ou superior. É necessário chamar setLogPanelEnabled: antes de chamar rebuildSlots. O painel não fica visível no cenário Minimal.

Desenvolvimento personalizado

Protocolo LogObserver

@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

Modelo de dados LogInfo

Propriedade

Tipo

Descrição

level

LogLevel

Nível do log (somente leitura).

tag

NSString *

Tag do log (somente leitura).

message

NSString *

Conteúdo da mensagem de log (somente leitura).

timestamp

NSDate *

Timestamp de geração do log (somente leitura).

threadName

NSString *

Nome da thread que gerou o log (somente leitura).

fileName

NSString *

Nome do arquivo de origem, como @"MyClass.m" (somente leitura).

line

NSInteger

Número da linha no source (somente leitura).

error

NSError *

Objeto de erro associado, podendo ser nil (somente leitura).

Método

Descrição

formattedString

Obtém a string de log formatada.

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

Inicializador designado.

initWithLevel:tag:message:

Inicializador de conveniência que captura automaticamente o timestamp e o nome da thread.

Formato de saída formatada:

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

Se houver um erro, uma linha extra é anexada:

Error: domain=xxx code=xxx userInfo=xxx

Exemplo: log observer personalizado para arquivo

A seguir, uma implementação completa de um log observer para arquivo:

@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
Nota

O callback onLog: é executado em uma fila serial em background. No entanto, para operações de I/O de arquivo, recomendamos usar uma fila de escrita separada para evitar o bloqueio da fila de despacho de logs. O bloqueio da fila pode afetar outros observers.

Exemplo: integração completa

// 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
Nota

O módulo PlayerKitUsages/UsageLogSystem fornece um exemplo completo de uso do sistema de logs. O exemplo inclui um FileLogObserver e uma interface para exibição dos logs.

Melhores práticas

Recomendações de configuração por ambiente

Ambiente

Chave mestra

console

Nível

Observer

Painel de logs

Desenvolvimento e depuração

YES

YES

Verbose

Opcional (painel de UI)

Opcional

Testes internos

YES

YES

Debug

Log em arquivo

NO

Ambiente de produção

YES

NO

Info

Log em arquivo + relatório remoto

NO

Cenários sensíveis

NO

NO

Erros comuns

Erro 1: atualize a interface diretamente no callback do observer

// ✗ 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;
    });
}

Erro 2: operações de bloqueio síncronas no 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...
    });
}

Erro 3: esquecer de remover o observer, causando referência circular

// ✗ 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];
}
Nota

Diferentemente do Dispatcher do sistema de notificações, o LogHub mantém uma referência forte aos observers. Se você não chamar removeObserver:, o observer não será liberado.

Referência da API

Níveis de log (LogLevel)

Nível

Valor da enumeração

Valor numérico

Descrição

Verbose

LogLevelVerbose

0

Mais detalhado; destinado a desenvolvimento e depuração.

Debug

LogLevelDebug

1

Informações de depuração.

Info

LogLevelInfo

2

Nível padrão, recomendado para produção.

Warn

LogLevelWarn

3

Problemas potenciais.

Error

LogLevelError

4

Mensagens de erro.

None

LogLevelNone

100

Desativa todos os logs.

Nota

O arquivo LogLevel.h também oferece a função inline LogLevelToString(), que converte um nível de log em uma string abreviada (V, D, I, W, E ou N).

API principal do LogHub

Propriedade / Método

Tipo

Descrição

+sharedHub

Método de classe

Obtém a instância singleton.

logEnabled

BOOL

Chave mestra de logs (padrão: YES).

logLevel

LogLevel

Nível de log (padrão: LogLevelInfo).

consoleLogEnabled

BOOL

Chave do console (padrão: YES).

v:msg:

Método de instância

Emite um log Verbose.

d:msg:

Método de instância

Emite um log Debug.

i:msg:

Método de instância

Emite um log Info.

w:msg:

Método de instância

Emite um log Warn.

e:msg:

Método de instância

Emite um log Error.

e:msg:error:

Método de instância

Emite um log Error com um NSError.

log:tag:msg:

Método de instância

Emite um log no nível especificado.

logLevel:file:line:message:error:

Método de instância

Método principal de log (usado pelas macros SLOG).

addObserver:

Método de instância

Adiciona um observer (referência forte; sem efeito se adicionado repetidamente).

removeObserver:

Método de instância

Remove um observer.

+levelToString:

Método de classe

Converte um nível em string (V/D/I/W/E/N).

+stringToLevel:

Método de classe

Converte uma string em nível (insensível a maiúsculas/minúsculas; retorna LogLevelInfo se não reconhecido).

API de atalho de logs do AliPlayerKit

Método

Descrição

+setLogLevel:

Defina o nível de log (deve ser chamado após setup).

+logLevel

Obtém o nível de log atual.

+enableConsoleLog:

Ative ou desative a saída de logs no console.

+isConsoleLogEnabled

Verifica se o log no console está ativado.

+setDebugModeEnabled:

Ative ou desative o modo de depuração.

+isDebugModeEnabled

Verifica se o modo de depuração está ativado.

+setLogPanelEnabled:

Ative ou desative o slot do painel de logs.

+isLogPanelEnabled

Verifica se o painel de logs está ativado.

Macros auxiliares SLOG

Macro

Nível

Forma expandida

SLOGV(fmt, ...)

Verbose

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

SLOGD(fmt, ...)

Debug

Igual à anterior, com nível Debug.

SLOGI(fmt, ...)

Info

Igual à anterior, com nível Info.

SLOGW(fmt, ...)

Warn

Igual à anterior, com nível Warn.

SLOGE(fmt, ...)

Error

Igual à anterior, com nível Error.

Propriedades do LogInfo

Propriedade

Tipo

Descrição

level

LogLevel

Nível do log.

tag

NSString *

Tag do log.

message

NSString *

Conteúdo da mensagem de log.

timestamp

NSDate *

Timestamp de geração do log.

threadName

NSString *

Nome da thread.

fileName

NSString *

Nome do arquivo de origem.

line

NSInteger

Número da linha no source.

error

NSError *

Objeto de erro associado (nullable).

formattedString

Método

Obtém a string de log formatada.

Protocolo LogObserver

Método

Obrigatório

Descrição

onLog:

Sim (@required)

Callback de saída de log, executado em uma fila serial em background.