---
source_url: https://www.pubnub.com/docs/sdks/c-core/migration-guides/c-core-v7-migration-guide
title: C-Core SDK 7.0.0 migration guide
updated_at: 2026-06-09T11:07:40.080Z
sdk_name: PubNub C/C++ Core SDK
sdk_version: 7.2.3
---

> Documentation Index
> For a curated overview of PubNub documentation, see: https://www.pubnub.com/docs/llms.txt
> For the full list of all documentation pages, see: https://www.pubnub.com/docs/llms-full.txt


# C-Core SDK 7.0.0 migration guide

PubNub C/C++ Core SDK, use the latest version: 7.2.3

This guide summarizes the differences between 6.X.X versions and 7.0.0 and shows how to migrate to C-Core SDK 7.0.0.

C-Core SDK version 7.0.0 makes DNS server configuration per-context, replaces the logging subsystem with an advanced pluggable logger architecture, and adds logging methods to the C++ wrapper class. This applies to all C-Core SDK flavors: C-Core, POSIX C, POSIX C++, Windows C, Windows C++, FreeRTOS, and Mbed.

:::tip Earlier migration guides
If you are upgrading from a version before 6.0.0, read the [C-Core SDK 6.0.0 migration guide](https://www.pubnub.com/docs/sdks/c-core/migration-guides/c-core-v6-migration-guide) first.
:::

## What has changed

See the major differences between versions:

| Feature | C-Core SDK 6.X.X | C-Core SDK 7.0.0 |
| --- | --- | --- |
| [DNS server functions](#dns-server-api) | Global (no context parameter) | Per-context (`pubnub_t* pb` added as first parameter) |
| [Logging header](#logging-subsystem) | `#include "core/pubnub_log.h"` | `#include "core/pubnub_logger.h"` |
| [Logging functions](#logging-subsystem) | `PUBNUB_LOG_PRINTF(...)` macros | `pubnub_log_text()`, `pubnub_log_text_formatted()`, `pubnub_log_object()`, `pubnub_log_error()` |
| [Log level enum](#log-level-changes) | Sequential: `NONE=0, ERROR=1, ... TRACE=5` | Bitmask: `TRACE=1, DEBUG=2, INFO=4, WARNING=8, ERROR=16, NONE=32` |
| [Compile-time level macro](#build-configuration) | `PUBNUB_LOG_LEVEL` | `PUBNUB_LOG_MIN_LEVEL` |
| [Custom output / runtime callback](#replace-pubnub_log_printf-override) | Override `PUBNUB_LOG_PRINTF` macro or `pubnub_set_log_callback(fn)` | Register custom `pubnub_logger_t` with `pubnub_logger_add(pb, logger)` |
| [WATCH_* macros](#replace-watch_-macros) | `WATCH_INT(x)`, `WATCH_STR(x)`, etc. | Removed. Use structured logging (`pubnub_log_object`) |
| [C++ wrapper](#c-wrapper) (POSIX C++, Windows C++) | No logging methods | New methods: `logger_add`, `logger_remove`, `set_log_level`, `log_text`, `log_object`, `log_error` |
| [Feature flags](#build-configuration) | Always compiled in | `PUBNUB_USE_LOGGER`, `PUBNUB_USE_DEFAULT_LOGGER` |

## Breaking changes

| Change | Platforms affected |
| --- | --- |
| [DNS server API](#dns-server-api) | All (C-Core, POSIX C, POSIX C++, Windows C, Windows C++, FreeRTOS, Mbed) |
| [Logging subsystem](#logging-subsystem) | All |
| [Log level changes](#log-level-changes) | All |
| [Build configuration](#build-configuration) | All |
| [C++ wrapper](#c-wrapper) | POSIX C++, Windows C++ |
| [Platform-specific default loggers](#platform-specific-default-loggers) | POSIX C, POSIX C++, Windows C, Windows C++, FreeRTOS, Microchip Harmony |

### DNS server API

Applies to: **All platforms**

Starting with 7.0.0, all 14 DNS server functions in `core/pubnub_dns_servers.h` require a `pubnub_t*` context as their first parameter. Previously, these functions operated on global state. Now DNS server configuration is per-context.

This change affects all functions guarded by `PUBNUB_SET_DNS_SERVERS`.

#### IPv4 functions

| Function | C-Core SDK 6.X.X | C-Core SDK 7.0.0 |
| --- | --- | --- |
| `pubnub_dns_set_primary_server_ipv4` | `(struct pubnub_ipv4_address ipv4)` | `(pubnub_t* pb, struct pubnub_ipv4_address ipv4)` |
| `pubnub_dns_set_secondary_server_ipv4` | `(struct pubnub_ipv4_address ipv4)` | `(pubnub_t* pb, struct pubnub_ipv4_address ipv4)` |
| `pubnub_dns_set_primary_server_ipv4_str` | `(char const* ipv4_str)` | `(pubnub_t* pb, char const* ipv4_str)` |
| `pubnub_dns_set_secondary_server_ipv4_str` | `(char const* ipv4_str)` | `(pubnub_t* pb, char const* ipv4_str)` |
| `pubnub_get_dns_primary_server_ipv4` | `(struct pubnub_ipv4_address* o_ipv4)` | `(pubnub_t* pb, struct pubnub_ipv4_address* o_ipv4)` |
| `pubnub_get_dns_secondary_server_ipv4` | `(struct pubnub_ipv4_address* o_ipv4)` | `(pubnub_t* pb, struct pubnub_ipv4_address* o_ipv4)` |
| `pubnub_dns_read_system_servers_ipv4` | `(struct pubnub_ipv4_address* o_ipv4, size_t n)` | `(pubnub_t* pb, struct pubnub_ipv4_address* o_ipv4, size_t n)` |

#### IPv6 functions (require PUBNUB_USE_IPV6)

| Function | C-Core SDK 6.X.X | C-Core SDK 7.0.0 |
| --- | --- | --- |
| `pubnub_dns_set_primary_server_ipv6` | `(struct pubnub_ipv6_address ipv6)` | `(pubnub_t* pb, struct pubnub_ipv6_address ipv6)` |
| `pubnub_dns_set_secondary_server_ipv6` | `(struct pubnub_ipv6_address ipv6)` | `(pubnub_t* pb, struct pubnub_ipv6_address ipv6)` |
| `pubnub_dns_set_primary_server_ipv6_str` | `(char const* ipv6_str)` | `(pubnub_t* pb, char const* ipv6_str)` |
| `pubnub_dns_set_secondary_server_ipv6_str` | `(char const* ipv6_str)` | `(pubnub_t* pb, char const* ipv6_str)` |
| `pubnub_get_dns_primary_server_ipv6` | `(struct pubnub_ipv6_address* o_ipv6)` | `(pubnub_t* pb, struct pubnub_ipv6_address* o_ipv6)` |
| `pubnub_get_dns_secondary_server_ipv6` | `(struct pubnub_ipv6_address* o_ipv6)` | `(pubnub_t* pb, struct pubnub_ipv6_address* o_ipv6)` |
| `pubnub_dns_read_system_servers_ipv6` | N/A (new in 6.2.0) | `(pubnub_t* pb, struct pubnub_ipv6_address* o_ipv6, size_t n)` |

:::note Fallback macros
The fallback macros (when `PUBNUB_SET_DNS_SERVERS` is disabled) also gained the `pb` parameter, so code using the macro forms also needs updating.
:::

###### Before (6.X.X)

```c
#include "core/pubnub_dns_servers.h"

/* DNS servers were global — no context needed */
struct pubnub_ipv4_address dns = {{8, 8, 8, 8}};
pubnub_dns_set_primary_server_ipv4(dns);
pubnub_dns_set_secondary_server_ipv4_str("8.8.4.4");

/* Read system DNS servers */
struct pubnub_ipv4_address servers[4];
int count = pubnub_dns_read_system_servers_ipv4(servers, 4);
```

###### After (7.0.0)

```c
#include "core/pubnub_dns_servers.h"

/* DNS servers are now per-context — pass pubnub_t* as first argument */
pubnub_t* pb = pubnub_alloc();
pubnub_init(pb, "pub-key", "sub-key");

struct pubnub_ipv4_address dns = {{8, 8, 8, 8}};
pubnub_dns_set_primary_server_ipv4(pb, dns);
pubnub_dns_set_secondary_server_ipv4_str(pb, "8.8.4.4");

/* Read system DNS servers — also requires context now */
struct pubnub_ipv4_address servers[4];
int count = pubnub_dns_read_system_servers_ipv4(pb, servers, 4);

/* IPv6 system DNS discovery (new in 6.2.0, requires PUBNUB_USE_IPV6) */
struct pubnub_ipv6_address servers6[4];
int count6 = pubnub_dns_read_system_servers_ipv6(pb, servers6, 4);
```

### Logging subsystem

Applies to: **All platforms**

Starting with 7.0.0, the SDK replaces its legacy logging subsystem (`core/pubnub_log.h`) with a new advanced logging system (`core/pubnub_logger.h`). The new system introduces per-context logging, multiple simultaneous logger support, structured data logging, network request/response logging, and runtime log level control.

The files `core/pubnub_log.h` and `core/pubnub_log.c` are deleted. Any direct references to them cause compilation errors.

#### Removed APIs

The following are deleted and cause compilation errors if referenced:

| Removed API | Replacement |
| --- | --- |
| `#include "core/pubnub_log.h"` | `#include "core/pubnub_logger.h"` |
| `PUBNUB_LOG_PRINTF(...)` | `pubnub_log_text_formatted(pb, level, location, format, ...)` |
| `PUBNUB_LOG_ERROR(...)`, `PUBNUB_LOG_WARNING(...)`, `PUBNUB_LOG_INFO(...)`, `PUBNUB_LOG_DEBUG(...)`, `PUBNUB_LOG_TRACE(...)` | `pubnub_log_text_formatted(pb, level, location, format, ...)` |
| `WATCH_INT(x)`, `WATCH_STR(x)`, `WATCH_ENUM(x)`, `WATCH_ULONG(x)` | `pubnub_log_object(pb, level, location, value, details)` |
| `pubnub_set_log_callback(fn)` / `PUBNUB_USE_LOG_CALLBACK` | Create a custom `pubnub_logger_t` and register with `pubnub_logger_add(pb, logger)`. `PUBNUB_USE_LOGGER` controls whether the logging subsystem is compiled in. |
| `PUBNUB_LOG_LEVEL` (compile-time macro) | `PUBNUB_LOG_MIN_LEVEL` |

#### New logging public API

All functions are part of the public C API in `core/pubnub_logger.h`.

##### Logger lifecycle

| Function | Description |
| --- | --- |
| `pubnub_logger_alloc(vtable, user_data)` | Create a custom logger with a vtable and optional user data. Returns `NULL` on failure. |
| `pubnub_logger_user_data(logger)` | Retrieve user data associated with a custom logger. |
| `pubnub_logger_free(logger)` | Free a custom logger. Calls the logger's `destroy()` callback if provided. Sets `*logger` to `NULL`. |

##### Logger registration

| Function | Description |
| --- | --- |
| `pubnub_logger_add(pb, logger)` | Register a custom logger with a PubNub context. Multiple loggers can be registered. Returns `0` on success. |
| `pubnub_logger_remove(pb, logger)` | Unregister a custom logger. Caller must still call `pubnub_logger_free()`. Returns `0` on success. |
| `pubnub_logger_remove_all(pb)` | Unregister all custom loggers. Caller must free each logger individually. |

##### Log level control

| Function | Description |
| --- | --- |
| `pubnub_logger_set_log_level(pb, level)` | Set the minimum log level. Messages below this level are not dispatched. |
| `pubnub_logger_log_level(pb)` | Get the current minimum log level. Default: `PUBNUB_LOG_LEVEL_DEBUG`. |

##### Logging functions

| Function | Description |
| --- | --- |
| `pubnub_log_text(pb, level, location, message)` | Log a plain text message. |
| `pubnub_log_text_formatted(pb, level, location, format, ...)` | Log a formatted text message (printf-style). |
| `pubnub_log_object(pb, level, location, value, details)` | Log a structured object/data. |
| `pubnub_log_error(pb, location, error_code, error_message, details)` | Log an error. Level is always `PUBNUB_LOG_LEVEL_ERROR`. |

#### Replace logging macros

##### Before (6.X.X)

```c
#include "core/pubnub_log.h"

PUBNUB_LOG_ERROR("Failed to publish: %d", result);
PUBNUB_LOG_DEBUG("Channel: %s", channel);
```

##### After (7.0.0)

```c
#include "core/pubnub_logger.h"

pubnub_log_text_formatted(pb, PUBNUB_LOG_LEVEL_ERROR, "app.c:42",
                          "Failed to publish: %d", result);
pubnub_log_text_formatted(pb, PUBNUB_LOG_LEVEL_DEBUG, "app.c:50",
                          "Channel: %s", channel);

/* Or use pubnub_log_text() for non-formatted messages */
pubnub_log_text(pb, PUBNUB_LOG_LEVEL_INFO, "app.c:60",
                "Subscription connected");
```

#### Replace PUBNUB_LOG_PRINTF override

##### Before (6.X.X)

```c
/* Compile-time macro override */
#define PUBNUB_LOG_PRINTF(...) my_log_func(__VA_ARGS__)
```

##### After (7.0.0)

```c
#include "core/pubnub_logger.h"

/* Runtime custom logger registration */
static void my_logger_handler(const pubnub_logger_t*      logger,
                               const pubnub_log_message_t* message) {
    if (message->message_type == PUBNUB_LOG_MESSAGE_TYPE_TEXT) {
        const pubnub_log_message_text_t* text =
            (const pubnub_log_message_text_t*)message;
        my_log_func("[%s] %s\n", message->pubnub_id, text->message);
    }
}

static const struct pubnub_logger_interface my_vtable = {
    .trace   = my_logger_handler,
    .debug   = my_logger_handler,
    .info    = my_logger_handler,
    .warn    = my_logger_handler,
    .error   = my_logger_handler,
    .destroy = NULL,
};

/* Register after creating context */
pubnub_logger_t* my_logger = pubnub_logger_alloc(&my_vtable, NULL);
pubnub_logger_add(pb, my_logger);
```

#### Replace pubnub_set_log_callback

##### Before (6.X.X)

```c
void my_callback(enum pubnub_log_level level, const char* message) {
    fprintf(log_file, "[%d] %s", level, message);
}
pubnub_set_log_callback(my_callback);
```

##### After (7.0.0)

```c
#include "core/pubnub_logger.h"

typedef struct {
    FILE* file;
} my_context;

static void my_handler(const pubnub_logger_t*      logger,
                        const pubnub_log_message_t* message) {
    my_context* ctx = (my_context*)pubnub_logger_user_data(
        (pubnub_logger_t*)logger);
    if (message->message_type == PUBNUB_LOG_MESSAGE_TYPE_TEXT) {
        const pubnub_log_message_text_t* text =
            (const pubnub_log_message_text_t*)message;
        fprintf(ctx->file, "[%s] %s\n", message->pubnub_id, text->message);
    }
}

static void my_destroy(pubnub_logger_t* logger) {
    my_context* ctx = (my_context*)pubnub_logger_user_data(logger);
    if (ctx->file) fclose(ctx->file);
    free(ctx);
}

static const struct pubnub_logger_interface file_vtable = {
    .trace = my_handler, .debug = my_handler, .info = my_handler,
    .warn = my_handler, .error = my_handler, .destroy = my_destroy,
};

/* Setup */
my_context* ctx = malloc(sizeof(*ctx));
ctx->file = fopen("pubnub.log", "a");
pubnub_logger_t* file_logger = pubnub_logger_alloc(&file_vtable, ctx);
pubnub_logger_add(pb, file_logger);
```

#### Replace WATCH_* macros

##### Before (6.X.X)

```c
WATCH_INT(result);
WATCH_STR(channel);
```

##### After (7.0.0)

```c
#include "core/pubnub_log_value.h"

pubnub_log_value_t params = pubnub_log_value_map_init();
PUBNUB_LOG_MAP_SET_NUMBER(&params, result)
PUBNUB_LOG_MAP_SET_STRING(&params, channel)
pubnub_log_object(pb, PUBNUB_LOG_LEVEL_DEBUG, "app.c:42",
                  &params, "debug values");
```

:::warning Structured logging scope
All `pubnub_log_value_t` structures and their string pointers live on the stack. All values, containers, and the log call must be in the same scope. If a value goes out of scope before the logging function reads it, you get undefined behavior.
:::

### Log level changes

Applies to: **All platforms**

The log level enum changed from sequential integers with reversed ordering to bitmask powers of 2 with natural ordering.

#### Before (6.X.X)

```c
/* Sequential integers, REVERSED ordering (NONE is lowest) */
enum pubnub_log_level {
    PUBNUB_LOG_LEVEL_NONE    = 0,   /* Logging disabled */
    PUBNUB_LOG_LEVEL_ERROR   = 1,
    PUBNUB_LOG_LEVEL_WARNING = 2,
    PUBNUB_LOG_LEVEL_INFO    = 3,
    PUBNUB_LOG_LEVEL_DEBUG   = 4,
    PUBNUB_LOG_LEVEL_TRACE   = 5    /* Most verbose */
};
/* Filter: if (level <= PUBNUB_LOG_LEVEL) → emit */
```

#### After (7.0.0)

```c
/* Bitmask powers of 2, NATURAL ordering (TRACE is lowest) */
enum pubnub_log_level {
    PUBNUB_LOG_LEVEL_TRACE   = (1 << 0),  /*  1 — Most verbose */
    PUBNUB_LOG_LEVEL_DEBUG   = (1 << 1),  /*  2 */
    PUBNUB_LOG_LEVEL_INFO    = (1 << 2),  /*  4 */
    PUBNUB_LOG_LEVEL_WARNING = (1 << 3),  /*  8 */
    PUBNUB_LOG_LEVEL_ERROR   = (1 << 4),  /* 16 */
    PUBNUB_LOG_LEVEL_NONE    = (1 << 5),  /* 32 — Logging disabled */
};
/* Filter: if (level >= minimum_level) → emit */
```

:::warning Comparison direction changed
If your code compares log level values numerically (for example, `if (level <= PUBNUB_LOG_LEVEL_INFO)`), the comparison direction has changed. In the old system `NONE < ERROR < TRACE`. In the new system `TRACE < DEBUG < INFO < WARNING < ERROR < NONE`.
:::

### Build configuration

Applies to: **All platforms**

#### Compile-time log level stripping

The compile-time macro for log level filtering has changed.

##### Before (6.X.X)

```bash
# Old build flag
-DPUBNUB_LOG_LEVEL=PUBNUB_LOG_LEVEL_WARNING
```

##### After (7.0.0)

```bash
# New build flag — uses short level names
-DPUBNUB_LOG_MIN_LEVEL=WARNING

# Other examples:
-DPUBNUB_LOG_MIN_LEVEL=TRACE    # Maximum verbosity
-DPUBNUB_LOG_MIN_LEVEL=DEBUG    # Default
-DPUBNUB_LOG_MIN_LEVEL=NONE     # Disable all logging at compile time
```

### C++ wrapper

Applies to: **POSIX C++**, **Windows C++**

New methods are added to the `pubnub::context` class in `cpp/pubnub_common.hpp`, guarded by `#if PUBNUB_USE_LOGGER`. These delegate directly to the C public API functions.

| Method | Description |
| --- | --- |
| `logger_add(pubnub_logger_t* logger)` | Register a custom logger. Returns `0` on success. |
| `logger_remove(pubnub_logger_t* logger)` | Unregister a custom logger. Returns `0` on success. |
| `logger_remove_all()` | Unregister all custom loggers. |
| `set_log_level(pubnub_log_level level)` | Set minimum log level for this context. |
| `log_level()` | Get current minimum log level. Default: `PUBNUB_LOG_LEVEL_DEBUG`. |
| `log_text(pubnub_log_level level, char const* location, char const* message)` | Log a plain text message. |
| `log_text(pubnub_log_level level, char const* location, std::string const& message)` | Log a text message from `std::string`. |
| `log_object(pubnub_log_level level, char const* location, pubnub_log_value_t const* message, char const* details)` | Log a structured object with optional details. |
| `log_error(char const* location, int error_code, char const* error_message, char const* details)` | Log an error (always `PUBNUB_LOG_LEVEL_ERROR`). |

#### Basic C++ logging

```cpp
#include "pubnub_common.hpp"

pubnub::context ctx("demo", "demo");

/* Log simple text messages */
ctx.log_text(PUBNUB_LOG_LEVEL_INFO,
             "main.cpp:10",
             "PubNub context initialized");

/* Log with std::string */
std::string msg = "Subscribing to channel: " + channel_name;
ctx.log_text(PUBNUB_LOG_LEVEL_DEBUG, "main.cpp:15", msg);

/* Log an error */
ctx.log_error("main.cpp:25", -1, "Connection failed", "Timeout after 30s");
```

#### Custom logger in C++

```cpp
#include "pubnub_common.hpp"
#include "core/pubnub_logger.h"

static void my_info_handler(const pubnub_logger_t*      logger,
                             const pubnub_log_message_t* message) {
    if (message->message_type == PUBNUB_LOG_MESSAGE_TYPE_TEXT) {
        const pubnub_log_message_text_t* text =
            (const pubnub_log_message_text_t*)message;
        std::cout << "[INFO] " << text->message << std::endl;
    }
}

static const struct pubnub_logger_interface my_vtable = {
    .trace   = NULL,
    .debug   = NULL,
    .info    = my_info_handler,
    .warn    = NULL,
    .error   = NULL,
    .destroy = NULL,
};

int main() {
    pubnub::context ctx("demo", "demo");

    /* Create and register custom logger */
    pubnub_logger_t* logger = pubnub_logger_alloc(&my_vtable, NULL);
    ctx.logger_add(logger);

    /* Set minimum level to INFO (skip TRACE and DEBUG) */
    ctx.set_log_level(PUBNUB_LOG_LEVEL_INFO);

    /* ... use PubNub ... */

    /* Cleanup */
    ctx.logger_remove(logger);
    pubnub_logger_free(&logger);
}
```

#### Feature flags

Two new macros control the logging subsystem. Both are defined in each platform's `pubnub_config.h` and default to `1` (enabled).

| Macro | Default | Description |
| --- | --- | --- |
| `PUBNUB_USE_LOGGER` | `1` | Enable/disable the entire logging subsystem. When `0`, all logging macros become no-ops and logger API functions are not compiled. |
| `PUBNUB_USE_DEFAULT_LOGGER` | `1` | Enable/disable the built-in default platform logger. When `0`, no logger is registered automatically — you must register your own via `pubnub_logger_add()`. |

#### New source files

If you maintain custom build scripts or Makefiles, add the following files.

##### Always required when PUBNUB_USE_LOGGER=1

| File | Purpose |
| --- | --- |
| `core/pubnub_logger.c` | Public logger API implementation |
| `core/pbcc_logger_manager.c` | Logger manager (dispatches to registered loggers) |
| `core/pubnub_log_value.c` | Structured log value types |

##### Required only when PUBNUB_USE_DEFAULT_LOGGER=1

Add exactly one platform-specific default logger:

| Platform | File |
| --- | --- |
| POSIX / Windows | `core/pubnub_stdio_logger.c` |
| FreeRTOS | `freertos/pubnub_freertos_logger.c` |
| Microchip Harmony | `microchip_harmony/pubnub_harmony_logger.c` |

### Platform-specific default loggers

Applies to: **All platforms** (each platform uses its own logger implementation)

When `PUBNUB_USE_DEFAULT_LOGGER` is `1` (default), each new PubNub context automatically registers a platform-appropriate logger.

| Platform | File | Output | Timestamps |
| --- | --- | --- | --- |
| POSIX / Windows | `core/pubnub_stdio_logger.c` | `fprintf(stdout)` for TRACE/DEBUG/INFO/WARN; `fprintf(stderr)` for ERROR | ISO 8601 with milliseconds |
| FreeRTOS | `freertos/pubnub_freertos_logger.c` | `printf()` for all levels | ISO 8601 when wall-clock available; `xTaskGetTickCount()` tick-based fallback |
| Microchip Harmony | `microchip_harmony/pubnub_harmony_logger.c` | `SYS_CONSOLE_PRINT()` for all levels | Raw Unix timestamp; `SYS_TMR_TickCountGet()` fallback |

##### Output format example (POSIX/Windows)

```text
2026-03-03T10:11:31.456Z PubNub-a1b2c3d4 DEBUG core/pubnub_coreapi.c:123 Publishing to channel 'my-channel'
```

## Migration steps

To migrate to C-Core SDK 7.0.0:

1. Update DNS server function calls. Add pubnub_t* context as the first argument to all DNS server functions: ActionDescriptionAdd pb as the first argument to all pubnub_dns_set_*, pubnub_get_dns_*, and pubnub_dns_read_system_servers_* callsAll 14 DNS functions (7 IPv4 + 7 IPv6) now require a pubnub_t* context. This also applies to fallback macros when PUBNUB_SET_DNS_SERVERS is disabled.
2. Update logging includes: ActionDescriptionReplace #include "core/pubnub_log.h" with #include "core/pubnub_logger.h"The old header file is deleted. For structured log values and convenience macros, also include core/pubnub_log_value.h.
3. Replace old logging macros with public API functions: ActionDescriptionReplace PUBNUB_LOG_ERROR(...), PUBNUB_LOG_WARNING(...), etc. with pubnub_log_text_formatted()The new function requires a pubnub_t* context, a log level, a location string, and a format string with arguments.Replace pubnub_log_text() for non-formatted messagesUse when you don't need printf-style formatting.
4. Replace PUBNUB_LOG_PRINTF override with runtime custom logger registration: ActionDescriptionRemove #define PUBNUB_LOG_PRINTF(...) overridesCreate a pubnub_logger_interface vtable and register a custom logger at runtime using pubnub_logger_alloc() and pubnub_logger_add().
5. Replace pubnub_set_log_callback with custom logger: ActionDescriptionRemove pubnub_set_log_callback() callsCreate a custom logger with a vtable and register it with pubnub_logger_add(). Use pubnub_logger_user_data() to access custom state from within callbacks.
6. Replace WATCH_* macros with structured logging: ActionDescriptionReplace WATCH_INT(x), WATCH_STR(x), etc.Use pubnub_log_value_t types and pubnub_log_object(). Convenience macros like PUBNUB_LOG_MAP_SET_NUMBER and PUBNUB_LOG_MAP_SET_STRING are available in core/pubnub_log_value.h.
7. Update compile-time level configuration: ActionDescriptionReplace -DPUBNUB_LOG_LEVEL=PUBNUB_LOG_LEVEL_WARNING with -DPUBNUB_LOG_MIN_LEVEL=WARNINGThe new macro uses short level names: TRACE, DEBUG, INFO, WARNING, ERROR, NONE.
8. Update runtime level filtering: ActionDescriptionUse pubnub_logger_set_log_level(pb, level) to control runtime filteringThe old system only supported compile-time filtering. The new system supports both compile-time stripping and runtime filtering per context.
9. (C++ only) Use new context methods for logging: ActionDescriptionUse ctx.logger_add(), ctx.set_log_level(), ctx.log_text(), etc.The pubnub::context class in pubnub_common.hpp provides C++ wrappers for all logging API functions. No include changes needed — core/pubnub_logger.h is automatically included when PUBNUB_USE_LOGGER is enabled.
10. Update build scripts. Add new source files if you maintain custom build scripts: ActionDescriptionAdd core/pubnub_logger.c, core/pbcc_logger_manager.c, core/pubnub_log_value.cAlways required when PUBNUB_USE_LOGGER=1 (default).Add exactly one platform-specific default logger fileRequired when PUBNUB_USE_DEFAULT_LOGGER=1 (default). See New source files for platform-specific file names.
11. Clean up custom loggers before freeing the PubNub context: ActionDescriptionCall pubnub_logger_remove(pb, logger) and pubnub_logger_free(&logger) before pubnub_free(pb)Custom loggers must be unregistered and freed before the context is freed. pubnub_logger_free() calls the logger's destroy() callback if provided.
12. Test your application. Pay special attention to DNS configuration, logging output, and any custom logging integrations.

## Additional resources

For API details, see the [C-Core SDK documentation](https://www.pubnub.com/docs/sdks/c-core). For the full logging reference, see [Logging](https://www.pubnub.com/docs/sdks/c-core/logging). For questions or issues, contact [PubNub support](https://support.pubnub.com/).