Darwin: Improve os_log integration (#23528)

* Prefer locally installed restyle-path script if it exists

* Simplify GetModuleName

* Remove unused / unimplemented GetMessageWithPrefix and related unused constants

* Remove duplicate defaults for CHIP_*_LOGGING and move CHIP_LOG_FILTERING to CHIPConfig.h

* Remove duplicate CHIP_SYSTEM_CONFIG_NO_LOCKING section

* Rename support:enforce_format to attributes and include DLLUtil.h in it

* Darwin: Integrate CHIP logging with os_log at the log macro level

Introduce CHIP_SYSTEM_CONFIG_PLATFORM_LOG that enables integrating with CHIP logging at the log macro level.

Note: ChipLog* macros are now statements (not expressions), so a few of usages of VerifyOr... macros required adjustments.

* Fix (unrelated?) clang-tidy error

* Add logging:force_stdio target that takes preference over the platform logging backend and use it for unit tests and cli tools (chip-tool etc)

* Darwin: Implement MTR_LOG_* via ChipLog* and rename MTRLogging.h to MTRLogging_Internal.h. Also compile all ObjC files as ObjC++.

* Darwin: Replace NSLog usages in Matter.framework with MTR_LOG_*

* Darwin: Re-add MTRLogging.h as a public header and expose MTRSetLogCallback()

* Darwin: Use log redirection in darwin-framework-tool to log to stdout.

* Review: Document `...` parameters that take statements in CodeUtils.h

* Review: some comments and tweaks

* Darwin: Add logging preferences plist
diff --git a/build/chip/chip_test_suite.gni b/build/chip/chip_test_suite.gni
index caaf06f..336450c 100644
--- a/build/chip/chip_test_suite.gni
+++ b/build/chip/chip_test_suite.gni
@@ -94,15 +94,9 @@
       public_deps = []
     }
 
-    # TODO: figure out a way to auto-define dependency on stdio logging.
-    #       This dep is required since libSupportLayer now does not include
-    #       a default implementation.
-    #
-    #       Tests such as TestInetEndPoint need to exercise the system event
-    #       loop however they do not seem to include a logging binding so this
-    #       is forcefully added here.
     if (current_os != "zephyr" && current_os != "mbed") {
-      public_deps += [ "${chip_root}/src/platform/logging:stdio" ]
+      # Depend on stdio logging, and have it take precedence over the default platform backend
+      public_deps += [ "${chip_root}/src/platform/logging:force_stdio" ]
     }
   }
 
diff --git a/examples/chip-tool/BUILD.gn b/examples/chip-tool/BUILD.gn
index a4e87b7..d870c1d 100644
--- a/examples/chip-tool/BUILD.gn
+++ b/examples/chip-tool/BUILD.gn
@@ -120,7 +120,10 @@
 executable("chip-tool") {
   sources = [ "main.cpp" ]
 
-  deps = [ ":chip-tool-utils" ]
+  deps = [
+    ":chip-tool-utils",
+    "${chip_root}/src/platform/logging:force_stdio",
+  ]
 
   output_dir = root_out_dir
 }
diff --git a/examples/chip-tool/commands/interactive/InteractiveCommands.cpp b/examples/chip-tool/commands/interactive/InteractiveCommands.cpp
index 380a6e3..de82f20 100644
--- a/examples/chip-tool/commands/interactive/InteractiveCommands.cpp
+++ b/examples/chip-tool/commands/interactive/InteractiveCommands.cpp
@@ -18,6 +18,8 @@
 
 #include "InteractiveCommands.h"
 
+#include <platform/logging/LogV.h>
+
 #include <editline.h>
 #include <iomanip>
 #include <sstream>
diff --git a/examples/darwin-framework-tool/commands/interactive/InteractiveCommands.mm b/examples/darwin-framework-tool/commands/interactive/InteractiveCommands.mm
index 7fe2d7d..a251d51 100644
--- a/examples/darwin-framework-tool/commands/interactive/InteractiveCommands.mm
+++ b/examples/darwin-framework-tool/commands/interactive/InteractiveCommands.mm
@@ -17,7 +17,8 @@
  */
 
 #include "InteractiveCommands.h"
-#import <Matter/Matter.h>
+
+#include <platform/logging/LogV.h>
 
 #include <editline.h>
 #include <iomanip>
diff --git a/examples/darwin-framework-tool/main.mm b/examples/darwin-framework-tool/main.mm
index f0aeab4..58a37eb 100644
--- a/examples/darwin-framework-tool/main.mm
+++ b/examples/darwin-framework-tool/main.mm
@@ -28,9 +28,15 @@
 #include <zap-generated/cluster/Commands.h>
 #include <zap-generated/test/Commands.h>
 
+#include <cstdio>
+
 int main(int argc, const char * argv[])
 {
     @autoreleasepool {
+        MTRSetLogCallback(MTRLogTypeDetail, ^(MTRLogType type, NSString * component, NSString * message) {
+            fprintf(stdout, "CHIP:%s: %s\n", component.UTF8String, message.UTF8String);
+        });
+
         Commands commands;
         registerCommandsPairing(commands);
         registerCommandsInteractive(commands);
diff --git a/examples/platform/linux/BUILD.gn b/examples/platform/linux/BUILD.gn
index 605c198..08580aa 100644
--- a/examples/platform/linux/BUILD.gn
+++ b/examples/platform/linux/BUILD.gn
@@ -70,6 +70,7 @@
     "${chip_root}/src/lib",
     "${chip_root}/src/lib/shell",
     "${chip_root}/src/lib/shell:shell_core",
+    "${chip_root}/src/platform/logging:force_stdio",
   ]
 
   if (chip_enable_transport_trace) {
diff --git a/scripts/helpers/restyle-diff.sh b/scripts/helpers/restyle-diff.sh
index 4701b0a..bf428dc 100755
--- a/scripts/helpers/restyle-diff.sh
+++ b/scripts/helpers/restyle-diff.sh
@@ -33,9 +33,12 @@
 CHIP_ROOT=$(cd "$here/../.." && pwd)
 
 restyle-paths() {
-    url=https://github.com/restyled-io/restyler/raw/main/bin/restyle-path
-
-    sh <(curl --location --proto "=https" --tlsv1.2 "$url" -sSf) "$@"
+    if hash restyle-path 2>/dev/null; then
+        command restyle-path "$@"
+    else
+        url=https://github.com/restyled-io/restyler/raw/main/bin/restyle-path
+        sh <(curl --location --proto "=https" --tlsv1.2 "$url" -sSf) "$@"
+    fi
 }
 
 cd "$CHIP_ROOT"
diff --git a/src/access/AccessControl.cpp b/src/access/AccessControl.cpp
index 0f6c80c..20b58ee 100644
--- a/src/access/AccessControl.cpp
+++ b/src/access/AccessControl.cpp
@@ -549,11 +549,11 @@
     const char * log = "unexpected error";
     IgnoreUnusedVariable(log); // logging may be disabled
 
-    AuthMode authMode;
-    FabricIndex fabricIndex;
-    Privilege privilege;
-    size_t subjectCount = 0;
-    size_t targetCount  = 0;
+    AuthMode authMode       = AuthMode::kNone;
+    FabricIndex fabricIndex = kUndefinedFabricIndex;
+    Privilege privilege     = static_cast<Privilege>(0);
+    size_t subjectCount     = 0;
+    size_t targetCount      = 0;
 
     SuccessOrExit(entry.GetAuthMode(authMode));
     SuccessOrExit(entry.GetFabricIndex(fabricIndex));
diff --git a/src/darwin/Framework/CHIP/MTRAsyncCallbackWorkQueue.mm b/src/darwin/Framework/CHIP/MTRAsyncCallbackWorkQueue.mm
index 65b8424..edb2265 100644
--- a/src/darwin/Framework/CHIP/MTRAsyncCallbackWorkQueue.mm
+++ b/src/darwin/Framework/CHIP/MTRAsyncCallbackWorkQueue.mm
@@ -19,7 +19,7 @@
 #import <os/lock.h>
 
 #import "MTRAsyncCallbackWorkQueue.h"
-#import "MTRLogging.h"
+#import "MTRLogging_Internal.h"
 
 #pragma mark - Class extensions
 
diff --git a/src/darwin/Framework/CHIP/MTRAttestationInfo.m b/src/darwin/Framework/CHIP/MTRAttestationInfo.mm
similarity index 100%
rename from src/darwin/Framework/CHIP/MTRAttestationInfo.m
rename to src/darwin/Framework/CHIP/MTRAttestationInfo.mm
diff --git a/src/darwin/Framework/CHIP/MTRBaseDevice.mm b/src/darwin/Framework/CHIP/MTRBaseDevice.mm
index a2996d7..c5cbd06 100644
--- a/src/darwin/Framework/CHIP/MTRBaseDevice.mm
+++ b/src/darwin/Framework/CHIP/MTRBaseDevice.mm
@@ -24,7 +24,7 @@
 #import "MTRCluster_internal.h"
 #import "MTRError_Internal.h"
 #import "MTREventTLVValueDecoder_Internal.h"
-#import "MTRLogging.h"
+#import "MTRLogging_Internal.h"
 #import "MTRSetupPayload_Internal.h"
 
 #include "app/ConcreteAttributePath.h"
diff --git a/src/darwin/Framework/CHIP/MTRCSRInfo.m b/src/darwin/Framework/CHIP/MTRCSRInfo.mm
similarity index 100%
rename from src/darwin/Framework/CHIP/MTRCSRInfo.m
rename to src/darwin/Framework/CHIP/MTRCSRInfo.mm
diff --git a/src/darwin/Framework/CHIP/MTRCertificates.mm b/src/darwin/Framework/CHIP/MTRCertificates.mm
index 39735bd..c1699d6 100644
--- a/src/darwin/Framework/CHIP/MTRCertificates.mm
+++ b/src/darwin/Framework/CHIP/MTRCertificates.mm
@@ -16,8 +16,8 @@
 
 #import "MTRCertificates.h"
 #import "MTRError_Internal.h"
-#import "MTRLogging.h"
-#import "MTRMemory.h"
+#import "MTRFramework.h"
+#import "MTRLogging_Internal.h"
 #import "MTROperationalCredentialsDelegate.h"
 #import "MTRP256KeypairBridge.h"
 #import "NSDataSpanConversion.h"
@@ -31,15 +31,17 @@
 
 @implementation MTRCertificates
 
++ (void)initialize
+{
+    MTRFrameworkInit();
+}
+
 + (MTRCertificateDERBytes _Nullable)createRootCertificate:(id<MTRKeypair>)keypair
                                                  issuerID:(NSNumber * _Nullable)issuerID
                                                  fabricID:(NSNumber * _Nullable)fabricID
                                                     error:(NSError * __autoreleasing *)error
 {
-    NSLog(@"Generating root certificate");
-
-    [MTRMemory ensureInit];
-
+    MTR_LOG_DEFAULT("Generating root certificate");
     NSData * rootCert = nil;
     CHIP_ERROR err = MTROperationalCredentialsDelegate::GenerateRootCertificate(keypair, issuerID, fabricID, &rootCert);
     if (error) {
@@ -47,7 +49,7 @@
     }
 
     if (err != CHIP_NO_ERROR) {
-        NSLog(@"Generating root certificate failed: %s", ErrorStr(err));
+        MTR_LOG_ERROR("Generating root certificate failed: %s", ErrorStr(err));
     }
 
     return rootCert;
@@ -60,10 +62,7 @@
                                                          fabricID:(NSNumber * _Nullable)fabricID
                                                             error:(NSError * __autoreleasing *)error
 {
-    NSLog(@"Generating intermediate certificate");
-
-    [MTRMemory ensureInit];
-
+    MTR_LOG_DEFAULT("Generating intermediate certificate");
     NSData * intermediate = nil;
     CHIP_ERROR err = MTROperationalCredentialsDelegate::GenerateIntermediateCertificate(
         rootKeypair, rootCertificate, intermediatePublicKey, issuerID, fabricID, &intermediate);
@@ -72,7 +71,7 @@
     }
 
     if (err != CHIP_NO_ERROR) {
-        NSLog(@"Generating intermediate certificate failed: %s", ErrorStr(err));
+        MTR_LOG_ERROR("Generating intermediate certificate failed: %s", ErrorStr(err));
     }
 
     return intermediate;
@@ -86,10 +85,7 @@
                                            caseAuthenticatedTags:(NSArray<NSNumber *> * _Nullable)caseAuthenticatedTags
                                                            error:(NSError * __autoreleasing _Nullable * _Nullable)error
 {
-    NSLog(@"Generating operational certificate");
-
-    [MTRMemory ensureInit];
-
+    MTR_LOG_DEFAULT("Generating operational certificate");
     NSData * opcert = nil;
     CHIP_ERROR err = MTROperationalCredentialsDelegate::GenerateOperationalCertificate(
         signingKeypair, signingCertificate, operationalPublicKey, fabricID, nodeID, caseAuthenticatedTags, &opcert);
@@ -98,7 +94,7 @@
     }
 
     if (err != CHIP_NO_ERROR) {
-        NSLog(@"Generating operational certificate failed: %s", ErrorStr(err));
+        MTR_LOG_ERROR("Generating operational certificate failed: %s", ErrorStr(err));
     }
 
     return opcert;
@@ -106,12 +102,10 @@
 
 + (BOOL)keypair:(id<MTRKeypair>)keypair matchesCertificate:(NSData *)certificate
 {
-    [MTRMemory ensureInit];
-
     P256PublicKey keypairPubKey;
     CHIP_ERROR err = MTRP256KeypairBridge::MatterPubKeyFromSecKeyRef(keypair.publicKey, &keypairPubKey);
     if (err != CHIP_NO_ERROR) {
-        NSLog(@"Can't extract public key from keypair: %s", ErrorStr(err));
+        MTR_LOG_ERROR("Can't extract public key from keypair: %s", ErrorStr(err));
         return NO;
     }
     P256PublicKeySpan keypairKeySpan(keypairPubKey.ConstBytes());
@@ -119,7 +113,7 @@
     P256PublicKey certPubKey;
     err = ExtractPubkeyFromX509Cert(AsByteSpan(certificate), certPubKey);
     if (err != CHIP_NO_ERROR) {
-        NSLog(@"Can't extract public key from certificate: %s", ErrorStr(err));
+        MTR_LOG_ERROR("Can't extract public key from certificate: %s", ErrorStr(err));
         return NO;
     }
     P256PublicKeySpan certKeySpan(certPubKey.ConstBytes());
@@ -129,12 +123,10 @@
 
 + (BOOL)isCertificate:(MTRCertificateDERBytes)certificate1 equalTo:(MTRCertificateDERBytes)certificate2
 {
-    [MTRMemory ensureInit];
-
     P256PublicKey pubKey1;
     CHIP_ERROR err = ExtractPubkeyFromX509Cert(AsByteSpan(certificate1), pubKey1);
     if (err != CHIP_NO_ERROR) {
-        NSLog(@"Can't extract public key from first certificate: %s", ErrorStr(err));
+        MTR_LOG_ERROR("Can't extract public key from first certificate: %s", ErrorStr(err));
         return NO;
     }
     P256PublicKeySpan keySpan1(pubKey1.ConstBytes());
@@ -142,7 +134,7 @@
     P256PublicKey pubKey2;
     err = ExtractPubkeyFromX509Cert(AsByteSpan(certificate2), pubKey2);
     if (err != CHIP_NO_ERROR) {
-        NSLog(@"Can't extract public key from second certificate: %s", ErrorStr(err));
+        MTR_LOG_ERROR("Can't extract public key from second certificate: %s", ErrorStr(err));
         return NO;
     }
     P256PublicKeySpan keySpan2(pubKey1.ConstBytes());
@@ -154,14 +146,14 @@
     ChipDN subject1;
     err = ExtractSubjectDNFromX509Cert(AsByteSpan(certificate1), subject1);
     if (err != CHIP_NO_ERROR) {
-        NSLog(@"Can't extract subject DN from first certificate: %s", ErrorStr(err));
+        MTR_LOG_ERROR("Can't extract subject DN from first certificate: %s", ErrorStr(err));
         return NO;
     }
 
     ChipDN subject2;
     err = ExtractSubjectDNFromX509Cert(AsByteSpan(certificate2), subject2);
     if (err != CHIP_NO_ERROR) {
-        NSLog(@"Can't extract subject DN from second certificate: %s", ErrorStr(err));
+        MTR_LOG_ERROR("Can't extract subject DN from second certificate: %s", ErrorStr(err));
         return NO;
     }
 
@@ -171,8 +163,6 @@
 + (NSData * _Nullable)createCertificateSigningRequest:(id<MTRKeypair>)keypair
                                                 error:(NSError * __autoreleasing _Nullable * _Nullable)error
 {
-    [MTRMemory ensureInit];
-
     MTRP256KeypairBridge keypairBridge;
     CHIP_ERROR err = CHIP_NO_ERROR;
     do {
@@ -206,7 +196,7 @@
     chip::MutableByteSpan chipCertBytes(chipCertBuffer);
 
     CHIP_ERROR errorCode = chip::Credentials::ConvertX509CertToChipCert(x509CertBytes, chipCertBytes);
-    MTR_LOG_ERROR("ConvertX509CertToChipCert: %{public}s", chip::ErrorStr(errorCode));
+    MTR_LOG_ERROR("ConvertX509CertToChipCert: %s", chip::ErrorStr(errorCode));
 
     if (errorCode != CHIP_NO_ERROR)
         return nil;
@@ -224,7 +214,7 @@
     CHIP_ERROR errorCode = chip::Credentials::ConvertChipCertToX509Cert(tlvCertBytes, derCertBytes);
 
     if (errorCode != CHIP_NO_ERROR) {
-        MTR_LOG_ERROR("ConvertChipCertToX509Cert: %{public}s", chip::ErrorStr(errorCode));
+        MTR_LOG_ERROR("ConvertChipCertToX509Cert: %s", chip::ErrorStr(errorCode));
         return nil;
     }
 
diff --git a/src/darwin/Framework/CHIP/MTRClusterStateCacheContainer.mm b/src/darwin/Framework/CHIP/MTRClusterStateCacheContainer.mm
index 81eb662..72c5517 100644
--- a/src/darwin/Framework/CHIP/MTRClusterStateCacheContainer.mm
+++ b/src/darwin/Framework/CHIP/MTRClusterStateCacheContainer.mm
@@ -23,7 +23,7 @@
 #import "MTRDeviceControllerXPCConnection.h"
 #import "MTRError.h"
 #import "MTRError_Internal.h"
-#import "MTRLogging.h"
+#import "MTRLogging_Internal.h"
 
 #include <app/InteractionModelEngine.h>
 #include <lib/support/ErrorStr.h>
diff --git a/src/darwin/Framework/CHIP/MTRCommissioningParameters.m b/src/darwin/Framework/CHIP/MTRCommissioningParameters.mm
similarity index 100%
rename from src/darwin/Framework/CHIP/MTRCommissioningParameters.m
rename to src/darwin/Framework/CHIP/MTRCommissioningParameters.mm
diff --git a/src/darwin/Framework/CHIP/MTRMemory.mm b/src/darwin/Framework/CHIP/MTRDefines.h
similarity index 69%
rename from src/darwin/Framework/CHIP/MTRMemory.mm
rename to src/darwin/Framework/CHIP/MTRDefines.h
index f6c94bf..0751dda 100644
--- a/src/darwin/Framework/CHIP/MTRMemory.mm
+++ b/src/darwin/Framework/CHIP/MTRDefines.h
@@ -1,4 +1,5 @@
 /**
+ *
  *    Copyright (c) 2022 Project CHIP Authors
  *
  *    Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,19 +15,12 @@
  *    limitations under the License.
  */
 
-#import "MTRMemory.h"
+#import <Foundation/Foundation.h>
 
-#include <lib/support/CHIPMem.h>
+#define MTR_EXPORT __attribute__((visibility("default")))
 
-@implementation MTRMemory
-
-+ (void)ensureInit
-{
-    static dispatch_once_t onceToken;
-    dispatch_once(&onceToken, ^{
-        // The malloc version of MemoryInit never fails.
-        chip::Platform::MemoryInit();
-    });
-}
-
-@end
+#ifdef __cplusplus
+#define MTR_EXTERN extern "C" MTR_EXPORT
+#else
+#define MTR_EXTERN extern MTR_EXPORT
+#endif
diff --git a/src/darwin/Framework/CHIP/MTRDevice.mm b/src/darwin/Framework/CHIP/MTRDevice.mm
index 1653737..a145394 100644
--- a/src/darwin/Framework/CHIP/MTRDevice.mm
+++ b/src/darwin/Framework/CHIP/MTRDevice.mm
@@ -25,7 +25,7 @@
 #import "MTRDevice_Internal.h"
 #import "MTRError_Internal.h"
 #import "MTREventTLVValueDecoder_Internal.h"
-#import "MTRLogging.h"
+#import "MTRLogging_Internal.h"
 
 #include "lib/core/CHIPError.h"
 #include "lib/core/DataModelTypes.h"
diff --git a/src/darwin/Framework/CHIP/MTRDeviceAttestationDelegateBridge.mm b/src/darwin/Framework/CHIP/MTRDeviceAttestationDelegateBridge.mm
index 4a489aa..2f0c7f9 100644
--- a/src/darwin/Framework/CHIP/MTRDeviceAttestationDelegateBridge.mm
+++ b/src/darwin/Framework/CHIP/MTRDeviceAttestationDelegateBridge.mm
@@ -18,6 +18,7 @@
 #import "MTRDeviceAttestationDelegateBridge.h"
 #import "MTRDeviceAttestationDelegate_Internal.h"
 #import "MTRError_Internal.h"
+#import "MTRLogging_Internal.h"
 #import "NSDataSpanConversion.h"
 
 void MTRDeviceAttestationDelegateBridge::OnDeviceAttestationCompleted(chip::Controller::DeviceCommissioner * deviceCommissioner,
@@ -25,7 +26,8 @@
     chip::Credentials::AttestationVerificationResult attestationResult)
 {
     dispatch_async(mQueue, ^{
-        NSLog(@"MTRDeviceAttestationDelegateBridge::OnDeviceAttestationFailed completed with result: %hu", attestationResult);
+        MTR_LOG_DEFAULT(
+            "MTRDeviceAttestationDelegateBridge::OnDeviceAttestationFailed completed with result: %hu", attestationResult);
 
         mResult = attestationResult;
 
diff --git a/src/darwin/Framework/CHIP/MTRDeviceController+XPC.m b/src/darwin/Framework/CHIP/MTRDeviceController+XPC.mm
similarity index 100%
rename from src/darwin/Framework/CHIP/MTRDeviceController+XPC.m
rename to src/darwin/Framework/CHIP/MTRDeviceController+XPC.mm
diff --git a/src/darwin/Framework/CHIP/MTRDeviceController.mm b/src/darwin/Framework/CHIP/MTRDeviceController.mm
index c872221..c3e1c71 100644
--- a/src/darwin/Framework/CHIP/MTRDeviceController.mm
+++ b/src/darwin/Framework/CHIP/MTRDeviceController.mm
@@ -27,7 +27,7 @@
 #import "MTRDevice_Internal.h"
 #import "MTRError_Internal.h"
 #import "MTRKeypair.h"
-#import "MTRLogging.h"
+#import "MTRLogging_Internal.h"
 #import "MTROperationalCredentialsDelegate.h"
 #import "MTRP256KeypairBridge.h"
 #import "MTRPersistentStorageDelegateBridge.h"
diff --git a/src/darwin/Framework/CHIP/MTRDeviceControllerDelegateBridge.mm b/src/darwin/Framework/CHIP/MTRDeviceControllerDelegateBridge.mm
index 3ac0883..bc7865a 100644
--- a/src/darwin/Framework/CHIP/MTRDeviceControllerDelegateBridge.mm
+++ b/src/darwin/Framework/CHIP/MTRDeviceControllerDelegateBridge.mm
@@ -18,6 +18,7 @@
 #import "MTRDeviceControllerDelegateBridge.h"
 #import "MTRDeviceController.h"
 #import "MTRError_Internal.h"
+#import "MTRLogging_Internal.h"
 
 MTRDeviceControllerDelegateBridge::MTRDeviceControllerDelegateBridge(void)
     : mDelegate(nil)
@@ -59,7 +60,7 @@
 
 void MTRDeviceControllerDelegateBridge::OnStatusUpdate(chip::Controller::DevicePairingDelegate::Status status)
 {
-    NSLog(@"DeviceControllerDelegate status updated: %d", status);
+    MTR_LOG_DEFAULT("DeviceControllerDelegate status updated: %d", status);
 
     id<MTRDeviceControllerDelegate> strongDelegate = mDelegate;
     MTRDeviceController * strongController = mController;
@@ -75,7 +76,7 @@
 
 void MTRDeviceControllerDelegateBridge::OnPairingComplete(CHIP_ERROR error)
 {
-    NSLog(@"DeviceControllerDelegate Pairing complete. Status %s", chip::ErrorStr(error));
+    MTR_LOG_DEFAULT("DeviceControllerDelegate Pairing complete. Status %s", chip::ErrorStr(error));
 
     id<MTRDeviceControllerDelegate> strongDelegate = mDelegate;
     MTRDeviceController * strongController = mController;
@@ -91,14 +92,14 @@
 
 void MTRDeviceControllerDelegateBridge::OnPairingDeleted(CHIP_ERROR error)
 {
-    NSLog(@"DeviceControllerDelegate Pairing deleted. Status %s", chip::ErrorStr(error));
+    MTR_LOG_DEFAULT("DeviceControllerDelegate Pairing deleted. Status %s", chip::ErrorStr(error));
 
     // This is never actually called; just do nothing.
 }
 
 void MTRDeviceControllerDelegateBridge::OnCommissioningComplete(chip::NodeId nodeId, CHIP_ERROR error)
 {
-    NSLog(@"DeviceControllerDelegate Commissioning complete. NodeId %llu Status %s", nodeId, chip::ErrorStr(error));
+    MTR_LOG_DEFAULT("DeviceControllerDelegate Commissioning complete. NodeId %llu Status %s", nodeId, chip::ErrorStr(error));
 
     id<MTRDeviceControllerDelegate> strongDelegate = mDelegate;
     MTRDeviceController * strongController = mController;
diff --git a/src/darwin/Framework/CHIP/MTRDeviceControllerFactory.mm b/src/darwin/Framework/CHIP/MTRDeviceControllerFactory.mm
index 9167cd0..81f53c4 100644
--- a/src/darwin/Framework/CHIP/MTRDeviceControllerFactory.mm
+++ b/src/darwin/Framework/CHIP/MTRDeviceControllerFactory.mm
@@ -25,8 +25,8 @@
 #import "MTRDeviceControllerStartupParams_Internal.h"
 #import "MTRDeviceController_Internal.h"
 #import "MTRError_Internal.h"
-#import "MTRLogging.h"
-#import "MTRMemory.h"
+#import "MTRFramework.h"
+#import "MTRLogging_Internal.h"
 #import "MTROTAProviderDelegateBridge.h"
 #import "MTRP256KeypairBridge.h"
 #import "MTRPersistentStorageDelegateBridge.h"
@@ -50,7 +50,6 @@
 static NSString * const kErrorPersistentStorageInit = @"Init failure while creating a persistent storage delegate";
 static NSString * const kErrorAttestationTrustStoreInit = @"Init failure while creating the attestation trust store";
 static NSString * const kErrorDACVerifierInit = @"Init failure while creating the device attestation verifier";
-static NSString * const kInfoFactoryShutdown = @"Shutting down the Matter controller factory";
 static NSString * const kErrorGroupProviderInit = @"Init failure while initializing group data provider";
 static NSString * const kErrorControllersInit = @"Init controllers array failure";
 static NSString * const kErrorControllerFactoryInit = @"Init failure while initializing controller factory";
@@ -85,6 +84,11 @@
 
 @implementation MTRDeviceControllerFactory
 
++ (void)initialize
+{
+    MTRFrameworkInit();
+}
+
 + (instancetype)sharedInstance
 {
     static MTRDeviceControllerFactory * factory = nil;
@@ -105,7 +109,6 @@
     _running = NO;
     _chipWorkQueue = DeviceLayer::PlatformMgrImpl().GetWorkQueue();
     _controllerFactory = &DeviceControllerFactory::GetInstance();
-    [MTRMemory ensureInit];
 
     _groupStorageDelegate = new chip::TestPersistentStorageDelegate();
     if ([self checkForInitError:(_groupStorageDelegate != nullptr) logMsg:kErrorGroupProviderInit]) {
@@ -414,7 +417,7 @@
         [_controllers[0] shutdown];
     }
 
-    MTR_LOG_DEBUG("%@", kInfoFactoryShutdown);
+    MTR_LOG_DEBUG("Shutting down the Matter controller factory");
     _controllerFactory->Shutdown();
 
     [self cleanupStartupObjects];
diff --git a/src/darwin/Framework/CHIP/MTRDeviceControllerOverXPC.m b/src/darwin/Framework/CHIP/MTRDeviceControllerOverXPC.mm
similarity index 99%
rename from src/darwin/Framework/CHIP/MTRDeviceControllerOverXPC.m
rename to src/darwin/Framework/CHIP/MTRDeviceControllerOverXPC.mm
index 929e479..b78f498 100644
--- a/src/darwin/Framework/CHIP/MTRDeviceControllerOverXPC.m
+++ b/src/darwin/Framework/CHIP/MTRDeviceControllerOverXPC.mm
@@ -21,7 +21,7 @@
 #import "MTRDeviceControllerXPCConnection.h"
 #import "MTRDeviceOverXPC.h"
 #import "MTRError.h"
-#import "MTRLogging.h"
+#import "MTRLogging_Internal.h"
 
 #import <Foundation/Foundation.h>
 
diff --git a/src/darwin/Framework/CHIP/MTRDeviceControllerStartupParams.mm b/src/darwin/Framework/CHIP/MTRDeviceControllerStartupParams.mm
index c2f0242..557864b 100644
--- a/src/darwin/Framework/CHIP/MTRDeviceControllerStartupParams.mm
+++ b/src/darwin/Framework/CHIP/MTRDeviceControllerStartupParams.mm
@@ -17,7 +17,7 @@
 #import "MTRDeviceControllerStartupParams.h"
 #import "MTRCertificates.h"
 #import "MTRDeviceControllerStartupParams_Internal.h"
-#import "MTRLogging.h"
+#import "MTRLogging_Internal.h"
 #import "MTRP256KeypairBridge.h"
 #import "NSDataSpanConversion.h"
 
diff --git a/src/darwin/Framework/CHIP/MTRDeviceControllerXPCConnection.m b/src/darwin/Framework/CHIP/MTRDeviceControllerXPCConnection.mm
similarity index 99%
rename from src/darwin/Framework/CHIP/MTRDeviceControllerXPCConnection.m
rename to src/darwin/Framework/CHIP/MTRDeviceControllerXPCConnection.mm
index a5513da..dc5cec1 100644
--- a/src/darwin/Framework/CHIP/MTRDeviceControllerXPCConnection.m
+++ b/src/darwin/Framework/CHIP/MTRDeviceControllerXPCConnection.mm
@@ -17,7 +17,7 @@
 
 #import "MTRDeviceControllerXPCConnection.h"
 #import "MTRDeviceControllerOverXPC.h"
-#import "MTRLogging.h"
+#import "MTRLogging_Internal.h"
 
 #import <Foundation/Foundation.h>
 
diff --git a/src/darwin/Framework/CHIP/MTRDeviceOverXPC.m b/src/darwin/Framework/CHIP/MTRDeviceOverXPC.mm
similarity index 99%
rename from src/darwin/Framework/CHIP/MTRDeviceOverXPC.m
rename to src/darwin/Framework/CHIP/MTRDeviceOverXPC.mm
index a746d0a..cea5e03 100644
--- a/src/darwin/Framework/CHIP/MTRDeviceOverXPC.m
+++ b/src/darwin/Framework/CHIP/MTRDeviceOverXPC.mm
@@ -23,7 +23,7 @@
 #import "MTRDeviceControllerOverXPC_Internal.h"
 #import "MTRDeviceControllerXPCConnection.h"
 #import "MTRError.h"
-#import "MTRLogging.h"
+#import "MTRLogging_Internal.h"
 
 NS_ASSUME_NONNULL_BEGIN
 
diff --git a/src/darwin/Framework/CHIP/MTRMemory.mm b/src/darwin/Framework/CHIP/MTRFramework.h
similarity index 68%
copy from src/darwin/Framework/CHIP/MTRMemory.mm
copy to src/darwin/Framework/CHIP/MTRFramework.h
index f6c94bf..0017081 100644
--- a/src/darwin/Framework/CHIP/MTRMemory.mm
+++ b/src/darwin/Framework/CHIP/MTRFramework.h
@@ -14,19 +14,7 @@
  *    limitations under the License.
  */
 
-#import "MTRMemory.h"
-
-#include <lib/support/CHIPMem.h>
-
-@implementation MTRMemory
-
-+ (void)ensureInit
-{
-    static dispatch_once_t onceToken;
-    dispatch_once(&onceToken, ^{
-        // The malloc version of MemoryInit never fails.
-        chip::Platform::MemoryInit();
-    });
-}
-
-@end
+/**
+ * Performs per-process initialization of the Matter stack.
+ */
+void MTRFrameworkInit();
diff --git a/src/darwin/Framework/CHIP/MTRFramework.mm b/src/darwin/Framework/CHIP/MTRFramework.mm
new file mode 100644
index 0000000..e6a0e67
--- /dev/null
+++ b/src/darwin/Framework/CHIP/MTRFramework.mm
@@ -0,0 +1,38 @@
+/**
+ *    Copyright (c) 2022 Project CHIP Authors
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#import "MTRFramework.h"
+
+#include <dispatch/dispatch.h>
+#include <lib/support/CHIPMem.h>
+#include <lib/support/logging/CHIPLogging.h>
+
+void MTRFrameworkInit()
+{
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        // Ensure Matter Platform::Memory is initialized.  This only needs
+        // to happen once per process, because in practice we just use
+        // malloc/free so there is nothing to initialize, so this just needs
+        // to happen to avoid debug assertions.  The malloc version of
+        // MemoryInit() never fails.
+        chip::Platform::MemoryInit();
+
+        // Suppress CHIP logging until we actually need it for redirection
+        // (see MTRSetLogCallback()). Logging to os_log is always enabled.
+        chip::Logging::SetLogFilter(chip::Logging::kLogCategory_None);
+    });
+}
diff --git a/src/darwin/Framework/CHIP/MTRLogging.h b/src/darwin/Framework/CHIP/MTRLogging.h
index f2bcb33..104c798 100644
--- a/src/darwin/Framework/CHIP/MTRLogging.h
+++ b/src/darwin/Framework/CHIP/MTRLogging.h
@@ -1,6 +1,6 @@
 /*
  *
- *    Copyright (c) 2020 Project CHIP Authors
+ *    Copyright (c) 2022 Project CHIP Authors
  *    All rights reserved.
  *
  *    Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,28 @@
  *    limitations under the License.
  */
 
-#import <os/log.h>
+#import <Matter/MTRDefines.h>
 
-#define MTR_LOG_FAULT(format, ...) os_log_fault(OS_LOG_DEFAULT, format, ##__VA_ARGS__)
-#define MTR_LOG_ERROR(format, ...) os_log_error(OS_LOG_DEFAULT, format, ##__VA_ARGS__)
-#define MTR_LOG_INFO(format, ...) os_log_info(OS_LOG_DEFAULT, format, ##__VA_ARGS__)
-#define MTR_LOG_DEBUG(format, ...) os_log_debug(OS_LOG_DEFAULT, format, ##__VA_ARGS__)
+NS_ASSUME_NONNULL_BEGIN
 
-#define MTR_LOG_METHOD_ENTRY()                                                                                                     \
-    ({ os_log_debug(OS_LOG_DEFAULT, "[<%@: %p> %@]", NSStringFromClass([self class]), self, NSStringFromSelector(_cmd)); })
+typedef NS_ENUM(NSInteger, MTRLogType) {
+    MTRLogTypeError = 1,
+    MTRLogTypeProgress = 2,
+    MTRLogTypeDetail = 3,
+};
+
+typedef void (^MTRLogCallback)(MTRLogType type, NSString * moduleName, NSString * message);
+
+/**
+ * Arranges for log messages from the Matter stack to be delivered to a callback block.
+ *
+ * @param logTypeThreshold only messages up to (and including) the specified log type will be delivered
+ * @param callback the block to call, or nil to disable the log callback.
+ *
+ * The callback block may be called concurrently and/or from arbitrary threads.
+ * It SHALL NOT call back directly or indirectly into any Matter APIs,
+ * nor block the calling thread for a non-trivial amount of time.
+ */
+MTR_EXTERN MTR_NEWLY_AVAILABLE void MTRSetLogCallback(MTRLogType logTypeThreshold, MTRLogCallback _Nullable callback);
+
+NS_ASSUME_NONNULL_END
diff --git a/src/darwin/Framework/CHIP/MTRLogging.mm b/src/darwin/Framework/CHIP/MTRLogging.mm
new file mode 100644
index 0000000..23b310a
--- /dev/null
+++ b/src/darwin/Framework/CHIP/MTRLogging.mm
@@ -0,0 +1,70 @@
+/*
+ *
+ *    Copyright (c) 2022 Project CHIP Authors
+ *    All rights reserved.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#import "MTRLogging_Internal.h"
+
+#import "MTRFramework.h"
+
+#import <algorithm>
+#import <atomic>
+#import <os/lock.h>
+
+using namespace chip::Logging;
+
+static_assert(MTRLogTypeError == (NSInteger) kLogCategory_Error, "MTRLogType* != kLogCategory_*");
+static_assert(MTRLogTypeProgress == (NSInteger) kLogCategory_Progress, "MTRLogType* != kLogCategory_*");
+static_assert(MTRLogTypeDetail == (NSInteger) kLogCategory_Detail, "MTRLogType* != kLogCategory_*");
+
+static os_unfair_lock logCallbackLock = OS_UNFAIR_LOCK_INIT;
+static MTRLogCallback logCallback = nil;
+
+static void MTRLogCallbackTrampoline(const char * moduleName, uint8_t category, const char * format, va_list args)
+{
+    os_unfair_lock_lock(&logCallbackLock);
+    MTRLogCallback callback = logCallback;
+    os_unfair_lock_unlock(&logCallbackLock);
+    if (!callback) {
+        return;
+    }
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wformat-nonliteral"
+    // Note: Format using NSString so that '%@' placeholders are supported
+    NSString * message = [[NSString alloc] initWithFormat:@(format) arguments:args];
+#pragma clang diagnostic pop
+
+    auto type = std::min(static_cast<MTRLogType>(category), MTRLogTypeDetail); // hide kLogCategory_Automation
+    callback(type, @(moduleName), message);
+}
+
+void MTRSetLogCallback(MTRLogType logTypeThreshold, MTRLogCallback _Nullable callback)
+{
+    MTRFrameworkInit();
+
+    os_unfair_lock_lock(&logCallbackLock);
+    if (callback) {
+        SetLogRedirectCallback(&MTRLogCallbackTrampoline);
+        SetLogFilter(static_cast<LogCategory>(std::min(std::max(logTypeThreshold, MTRLogTypeError), MTRLogTypeDetail)));
+        logCallback = callback;
+    } else {
+        logCallback = nil;
+        SetLogFilter(kLogCategory_None);
+        SetLogRedirectCallback(nullptr);
+    }
+    os_unfair_lock_unlock(&logCallbackLock);
+}
diff --git a/src/darwin/Framework/CHIP/MTRLogging_Internal.h b/src/darwin/Framework/CHIP/MTRLogging_Internal.h
new file mode 100644
index 0000000..9b2d2fc
--- /dev/null
+++ b/src/darwin/Framework/CHIP/MTRLogging_Internal.h
@@ -0,0 +1,26 @@
+/*
+ *
+ *    Copyright (c) 2020 Project CHIP Authors
+ *    All rights reserved.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#import <Matter/MTRLogging.h>
+
+#include <lib/support/logging/CHIPLogging.h>
+
+#define MTR_LOG_ERROR(msg, ...) ChipLogError(NotSpecified, msg, ##__VA_ARGS__)
+#define MTR_LOG_DEFAULT(msg, ...) ChipLogProgress(NotSpecified, msg, ##__VA_ARGS__)
+#define MTR_LOG_INFO(msg, ...) ChipLogDetail(NotSpecified, msg, ##__VA_ARGS__)
+#define MTR_LOG_DEBUG(msg, ...) ChipLogDetail(NotSpecified, msg, ##__VA_ARGS__) // same as INFO
diff --git a/src/darwin/Framework/CHIP/MTRManualSetupPayloadParser.mm b/src/darwin/Framework/CHIP/MTRManualSetupPayloadParser.mm
index fc493af..3a0435d 100644
--- a/src/darwin/Framework/CHIP/MTRManualSetupPayloadParser.mm
+++ b/src/darwin/Framework/CHIP/MTRManualSetupPayloadParser.mm
@@ -17,8 +17,8 @@
 #import "MTRManualSetupPayloadParser.h"
 
 #import "MTRError_Internal.h"
-#import "MTRLogging.h"
-#import "MTRMemory.h"
+#import "MTRFramework.h"
+#import "MTRLogging_Internal.h"
 #import "MTRSetupPayload_Internal.h"
 
 #import <setup_payload/ManualSetupPayloadParser.h>
@@ -29,10 +29,14 @@
     chip::ManualSetupPayloadParser * _chipManualSetupPayloadParser;
 }
 
++ (void)initialize
+{
+    MTRFrameworkInit();
+}
+
 - (id)initWithDecimalStringRepresentation:(NSString *)decimalStringRepresentation
 {
     if (self = [super init]) {
-        [MTRMemory ensureInit];
         _decimalStringRepresentation = decimalStringRepresentation;
         _chipManualSetupPayloadParser = new chip::ManualSetupPayloadParser(std::string([decimalStringRepresentation UTF8String]));
     }
diff --git a/src/darwin/Framework/CHIP/MTRMemory.h b/src/darwin/Framework/CHIP/MTRMemory.h
deleted file mode 100644
index 124e47e..0000000
--- a/src/darwin/Framework/CHIP/MTRMemory.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
- *    Copyright (c) 2022 Project CHIP Authors
- *
- *    Licensed under the Apache License, Version 2.0 (the "License");
- *    you may not use this file except in compliance with the License.
- *    You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- */
-
-#pragma once
-
-/**
- * Utility to initialize the Matter memory subsystem.  Not a public framework
- * header.
- */
-
-#import <Foundation/Foundation.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface MTRMemory : NSObject
-/**
- * Ensure Matter Platform::Memory is initialized.  This only needs to happen
- * once per process, because in practice we just use malloc/free so there is
- * nothing to initialize, so this just needs to happen to avoid debug
- * assertions.  This class handles ensuring the initialization only happens
- * once.
- */
-+ (void)ensureInit;
-
-@end
-
-NS_ASSUME_NONNULL_END
diff --git a/src/darwin/Framework/CHIP/MTROnboardingPayloadParser.m b/src/darwin/Framework/CHIP/MTROnboardingPayloadParser.mm
similarity index 100%
rename from src/darwin/Framework/CHIP/MTROnboardingPayloadParser.m
rename to src/darwin/Framework/CHIP/MTROnboardingPayloadParser.mm
diff --git a/src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.mm b/src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.mm
index 0703f4c..ba11b3c 100644
--- a/src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.mm
+++ b/src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.mm
@@ -21,10 +21,8 @@
 
 #import <Security/Security.h>
 
-#include <Security/SecKey.h>
-
 #import "MTRCertificates.h"
-#import "MTRLogging.h"
+#import "MTRLogging_Internal.h"
 #import "NSDataSpanConversion.h"
 
 #include <controller/CommissioningDelegate.h>
@@ -94,12 +92,12 @@
     uint32_t validityStart, validityEnd;
 
     if (!ToChipEpochTime(0, validityStart)) {
-        NSLog(@"Failed in computing certificate validity start date");
+        MTR_LOG_ERROR("Failed in computing certificate validity start date");
         return CHIP_ERROR_INTERNAL;
     }
 
     if (!ToChipEpochTime(kCertificateValiditySecs, validityEnd)) {
-        NSLog(@"Failed in computing certificate validity end date");
+        MTR_LOG_ERROR("Failed in computing certificate validity end date");
         return CHIP_ERROR_INTERNAL;
     }
 
@@ -378,12 +376,12 @@
     uint32_t validityStart, validityEnd;
 
     if (!ToChipEpochTime(0, validityStart)) {
-        NSLog(@"Failed in computing certificate validity start date");
+        MTR_LOG_ERROR("Failed in computing certificate validity start date");
         return CHIP_ERROR_INTERNAL;
     }
 
     if (!ToChipEpochTime(kCertificateValiditySecs, validityEnd)) {
-        NSLog(@"Failed in computing certificate validity end date");
+        MTR_LOG_ERROR("Failed in computing certificate validity end date");
         return CHIP_ERROR_INTERNAL;
     }
 
@@ -428,12 +426,12 @@
     uint32_t validityStart, validityEnd;
 
     if (!ToChipEpochTime(0, validityStart)) {
-        NSLog(@"Failed in computing certificate validity start date");
+        MTR_LOG_ERROR("Failed in computing certificate validity start date");
         return CHIP_ERROR_INTERNAL;
     }
 
     if (!ToChipEpochTime(kCertificateValiditySecs, validityEnd)) {
-        NSLog(@"Failed in computing certificate validity end date");
+        MTR_LOG_ERROR("Failed in computing certificate validity end date");
         return CHIP_ERROR_INTERNAL;
     }
 
diff --git a/src/darwin/Framework/CHIP/MTRP256KeypairBridge.mm b/src/darwin/Framework/CHIP/MTRP256KeypairBridge.mm
index c1045a4..d253baa 100644
--- a/src/darwin/Framework/CHIP/MTRP256KeypairBridge.mm
+++ b/src/darwin/Framework/CHIP/MTRP256KeypairBridge.mm
@@ -18,11 +18,11 @@
 #import "MTRP256KeypairBridge.h"
 #import "NSDataSpanConversion.h"
 
-#import <Security/SecKey.h>
+#import <Security/Security.h>
 #include <string>
 
 #import "MTRKeypair.h"
-#import "MTRLogging.h"
+#import "MTRLogging_Internal.h"
 
 using namespace chip::Crypto;
 
@@ -31,7 +31,7 @@
     if (![keypair respondsToSelector:@selector(signMessageECDSA_DER:)]
         && ![keypair respondsToSelector:@selector(signMessageECDSA_RAW:)]) {
         // Not a valid MTRKeypair implementation.
-        NSLog(@"Keypair does not support message signing");
+        MTR_LOG_ERROR("Keypair does not support message signing");
         return CHIP_ERROR_INVALID_ARGUMENT;
     }
 
diff --git a/src/darwin/Framework/CHIP/MTRPersistentStorageDelegateBridge.mm b/src/darwin/Framework/CHIP/MTRPersistentStorageDelegateBridge.mm
index fdcde68..69e4103 100644
--- a/src/darwin/Framework/CHIP/MTRPersistentStorageDelegateBridge.mm
+++ b/src/darwin/Framework/CHIP/MTRPersistentStorageDelegateBridge.mm
@@ -17,6 +17,8 @@
 
 #import "MTRPersistentStorageDelegateBridge.h"
 
+#import "MTRLogging_Internal.h"
+
 #define LOG_DEBUG_PERSISTENT_STORAGE_DELEGATE 0
 
 MTRPersistentStorageDelegateBridge::MTRPersistentStorageDelegateBridge(id<MTRStorage> delegate)
@@ -38,7 +40,7 @@
 
     dispatch_sync(mWorkQueue, ^{
 #if LOG_DEBUG_PERSISTENT_STORAGE_DELEGATE
-        NSLog(@"PersistentStorageDelegate Sync Get Value for Key: %@", keyString);
+        MTR_LOG_DEBUG("PersistentStorageDelegate Sync Get Value for Key: %@", keyString);
 #endif
 
         NSData * value = [mDelegate storageDataForKey:keyString];
@@ -81,7 +83,7 @@
     __block CHIP_ERROR error = CHIP_NO_ERROR;
     dispatch_sync(mWorkQueue, ^{
 #if LOG_DEBUG_PERSISTENT_STORAGE_DELEGATE
-        NSLog(@"PersistentStorageDelegate Set Key %@", keyString);
+        MTR_LOG_DEBUG("PersistentStorageDelegate Set Key %@", keyString);
 #endif
 
         if ([mDelegate setStorageData:valueData forKey:keyString] == NO) {
@@ -99,7 +101,7 @@
     __block CHIP_ERROR error = CHIP_NO_ERROR;
     dispatch_sync(mWorkQueue, ^{
 #if LOG_DEBUG_PERSISTENT_STORAGE_DELEGATE
-        NSLog(@"PersistentStorageDelegate Delete Key: %@", keyString);
+        MTR_LOG_DEBUG("PersistentStorageDelegate Delete Key: %@", keyString);
 #endif
 
         if ([mDelegate removeStorageDataForKey:keyString] == NO) {
diff --git a/src/darwin/Framework/CHIP/MTRQRCodeSetupPayloadParser.mm b/src/darwin/Framework/CHIP/MTRQRCodeSetupPayloadParser.mm
index 8d0354c..bbb8042 100644
--- a/src/darwin/Framework/CHIP/MTRQRCodeSetupPayloadParser.mm
+++ b/src/darwin/Framework/CHIP/MTRQRCodeSetupPayloadParser.mm
@@ -17,8 +17,8 @@
 
 #import "MTRQRCodeSetupPayloadParser.h"
 #import "MTRError_Internal.h"
-#import "MTRLogging.h"
-#import "MTRMemory.h"
+#import "MTRFramework.h"
+#import "MTRLogging_Internal.h"
 #import "MTRSetupPayload_Internal.h"
 
 #import <setup_payload/QRCodeSetupPayloadParser.h>
@@ -29,10 +29,14 @@
     chip::QRCodeSetupPayloadParser * _chipQRCodeSetupPayloadParser;
 }
 
++ (void)initialize
+{
+    MTRFrameworkInit();
+}
+
 - (id)initWithBase38Representation:(NSString *)base38Representation
 {
     if (self = [super init]) {
-        [MTRMemory ensureInit];
         _base38Representation = base38Representation;
         _chipQRCodeSetupPayloadParser = new chip::QRCodeSetupPayloadParser(std::string([base38Representation UTF8String]));
     }
diff --git a/src/darwin/Framework/CHIP/MTRThreadOperationalDataset.mm b/src/darwin/Framework/CHIP/MTRThreadOperationalDataset.mm
index fb50d87..dc8876b 100644
--- a/src/darwin/Framework/CHIP/MTRThreadOperationalDataset.mm
+++ b/src/darwin/Framework/CHIP/MTRThreadOperationalDataset.mm
@@ -17,7 +17,7 @@
 
 #import "MTRThreadOperationalDataset.h"
 
-#include "MTRLogging.h"
+#include "MTRLogging_Internal.h"
 #include <lib/support/Span.h>
 #include <lib/support/ThreadOperationalDataset.h>
 
diff --git a/src/darwin/Framework/CHIP/Matter.h b/src/darwin/Framework/CHIP/Matter.h
index 5fd4b14..179c284 100644
--- a/src/darwin/Framework/CHIP/Matter.h
+++ b/src/darwin/Framework/CHIP/Matter.h
@@ -37,6 +37,7 @@
 #import <Matter/MTRClusters.h>
 #import <Matter/MTRCommandPayloadsObjc.h>
 #import <Matter/MTRCommissioningParameters.h>
+#import <Matter/MTRDefines.h>
 #import <Matter/MTRDevice.h>
 #import <Matter/MTRDeviceAttestationDelegate.h>
 #import <Matter/MTRDeviceController+XPC.h>
@@ -46,6 +47,7 @@
 #import <Matter/MTRDeviceControllerStartupParams.h>
 #import <Matter/MTRError.h>
 #import <Matter/MTRKeypair.h>
+#import <Matter/MTRLogging.h>
 #import <Matter/MTRManualSetupPayloadParser.h>
 #import <Matter/MTRNOCChainIssuer.h>
 #import <Matter/MTROTAHeader.h>
diff --git a/src/darwin/Framework/CHIP/Resources/Logging/com.csa.matter.plist b/src/darwin/Framework/CHIP/Resources/Logging/com.csa.matter.plist
new file mode 100644
index 0000000..6826105
--- /dev/null
+++ b/src/darwin/Framework/CHIP/Resources/Logging/com.csa.matter.plist
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>DEFAULT-OPTIONS</key>
+	<dict>
+		<key>Default-Privacy-Setting</key>
+		<string>public</string>
+		<key>Level</key>
+		<dict>
+			<key>Enable</key>
+			<string>info</string>
+			<key>Persist</key>
+			<string>default</string>
+		</dict>
+	</dict>
+</dict>
+</plist>
diff --git a/src/darwin/Framework/CHIP/templates/MTRClusters-src.zapt b/src/darwin/Framework/CHIP/templates/MTRClusters-src.zapt
index b37dd16..dcb06b5 100644
--- a/src/darwin/Framework/CHIP/templates/MTRClusters-src.zapt
+++ b/src/darwin/Framework/CHIP/templates/MTRClusters-src.zapt
@@ -12,7 +12,7 @@
 #import "MTRCluster_internal.h"
 #import "MTRStructsObjc.h"
 #import "MTRCommandPayloadsObjc.h"
-#import "MTRLogging.h"
+#import "MTRLogging_Internal.h"
 
 #include <lib/support/CHIPListUtils.h>
 #include <platform/CHIPDeviceLayer.h>
diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm
index f0d5060..46da7e4 100644
--- a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm
+++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm
@@ -26,7 +26,7 @@
 #import "MTRCommandPayloadsObjc.h"
 #import "MTRDevice.h"
 #import "MTRDevice_Internal.h"
-#import "MTRLogging.h"
+#import "MTRLogging_Internal.h"
 #import "MTRStructsObjc.h"
 
 #include <lib/support/CHIPListUtils.h>
diff --git a/src/darwin/Framework/Matter.xcodeproj/project.pbxproj b/src/darwin/Framework/Matter.xcodeproj/project.pbxproj
index a839438..af1f6c3 100644
--- a/src/darwin/Framework/Matter.xcodeproj/project.pbxproj
+++ b/src/darwin/Framework/Matter.xcodeproj/project.pbxproj
@@ -33,10 +33,15 @@
 		2CB7163F252F731E0026E2BB /* MTRDeviceControllerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 2CB7163E252F731E0026E2BB /* MTRDeviceControllerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		2FD775552695557E00FF4B12 /* error-mapping.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2FD775542695557E00FF4B12 /* error-mapping.cpp */; };
 		3CF134A7289D8ADA0017A19E /* MTRCSRInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 3CF134A6289D8AD90017A19E /* MTRCSRInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
-		3CF134A9289D8D800017A19E /* MTRCSRInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 3CF134A8289D8D800017A19E /* MTRCSRInfo.m */; };
+		3CF134A9289D8D800017A19E /* MTRCSRInfo.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3CF134A8289D8D800017A19E /* MTRCSRInfo.mm */; };
 		3CF134AB289D8DF70017A19E /* MTRAttestationInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 3CF134AA289D8DF70017A19E /* MTRAttestationInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
-		3CF134AD289D8E570017A19E /* MTRAttestationInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 3CF134AC289D8E570017A19E /* MTRAttestationInfo.m */; };
+		3CF134AD289D8E570017A19E /* MTRAttestationInfo.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3CF134AC289D8E570017A19E /* MTRAttestationInfo.mm */; };
 		3CF134AF289D90FF0017A19E /* MTRNOCChainIssuer.h in Headers */ = {isa = PBXBuildFile; fileRef = 3CF134AE289D90FF0017A19E /* MTRNOCChainIssuer.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		3D69868529383096007314E7 /* com.csa.matter.plist in Copy Logging Preferences */ = {isa = PBXBuildFile; fileRef = 3D69868029382EF4007314E7 /* com.csa.matter.plist */; };
+		3DECCB6E29347D2D00585AEC /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DECCB6D29347D2C00585AEC /* Security.framework */; };
+		3DECCB702934AECD00585AEC /* MTRLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DECCB6F2934AC1C00585AEC /* MTRLogging.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		3DECCB722934AFE200585AEC /* MTRLogging.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3DECCB712934AFE200585AEC /* MTRLogging.mm */; };
+		3DECCB742934C21B00585AEC /* MTRDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DECCB732934C21B00585AEC /* MTRDefines.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		5112F606287CD2C100B827E7 /* privilege-storage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5112F605287CD2C100B827E7 /* privilege-storage.cpp */; };
 		511913FB28C100EF009235E9 /* MTRBaseSubscriptionCallback.mm in Sources */ = {isa = PBXBuildFile; fileRef = 511913F928C100EF009235E9 /* MTRBaseSubscriptionCallback.mm */; };
 		511913FC28C100EF009235E9 /* MTRBaseSubscriptionCallback.h in Headers */ = {isa = PBXBuildFile; fileRef = 511913FA28C100EF009235E9 /* MTRBaseSubscriptionCallback.h */; };
@@ -50,8 +55,8 @@
 		514304202914CED9004DC7FE /* generic-callback-stubs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5143041F2914CED9004DC7FE /* generic-callback-stubs.cpp */; };
 		51431AF927D2973E008A7943 /* MTRIMDispatch.mm in Sources */ = {isa = PBXBuildFile; fileRef = 51431AF827D2973E008A7943 /* MTRIMDispatch.mm */; };
 		51431AFB27D29CA4008A7943 /* ota-provider.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 51431AFA27D29CA4008A7943 /* ota-provider.cpp */; };
-		515C1C6F284F9FFB00A48F0C /* MTRMemory.mm in Sources */ = {isa = PBXBuildFile; fileRef = 515C1C6D284F9FFB00A48F0C /* MTRMemory.mm */; };
-		515C1C70284F9FFB00A48F0C /* MTRMemory.h in Headers */ = {isa = PBXBuildFile; fileRef = 515C1C6E284F9FFB00A48F0C /* MTRMemory.h */; };
+		515C1C6F284F9FFB00A48F0C /* MTRFramework.mm in Sources */ = {isa = PBXBuildFile; fileRef = 515C1C6D284F9FFB00A48F0C /* MTRFramework.mm */; };
+		515C1C70284F9FFB00A48F0C /* MTRFramework.h in Headers */ = {isa = PBXBuildFile; fileRef = 515C1C6E284F9FFB00A48F0C /* MTRFramework.h */; };
 		51669AF02913204400F4AA36 /* MTRBackwardsCompatTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 51669AEF2913204400F4AA36 /* MTRBackwardsCompatTests.m */; };
 		517BF3F0282B62B800A8B7DB /* MTRCertificates.h in Headers */ = {isa = PBXBuildFile; fileRef = 517BF3EE282B62B800A8B7DB /* MTRCertificates.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		517BF3F1282B62B800A8B7DB /* MTRCertificates.mm in Sources */ = {isa = PBXBuildFile; fileRef = 517BF3EF282B62B800A8B7DB /* MTRCertificates.mm */; };
@@ -70,15 +75,15 @@
 		51E51FC0282AD37A00FC978D /* MTRDeviceControllerStartupParams_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 51E51FBD282AD37A00FC978D /* MTRDeviceControllerStartupParams_Internal.h */; };
 		51E51FC1282AD37A00FC978D /* MTRDeviceControllerStartupParams.mm in Sources */ = {isa = PBXBuildFile; fileRef = 51E51FBE282AD37A00FC978D /* MTRDeviceControllerStartupParams.mm */; };
 		5A60370827EA1FF60020DB79 /* MTRClusterStateCacheContainer+XPC.h in Headers */ = {isa = PBXBuildFile; fileRef = 5A60370727EA1FF60020DB79 /* MTRClusterStateCacheContainer+XPC.h */; };
-		5A6FEC9027B563D900F25F42 /* MTRDeviceControllerOverXPC.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A6FEC8F27B563D900F25F42 /* MTRDeviceControllerOverXPC.m */; };
+		5A6FEC9027B563D900F25F42 /* MTRDeviceControllerOverXPC.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5A6FEC8F27B563D900F25F42 /* MTRDeviceControllerOverXPC.mm */; };
 		5A6FEC9227B5669C00F25F42 /* MTRDeviceControllerOverXPC.h in Headers */ = {isa = PBXBuildFile; fileRef = 5A6FEC8D27B5624E00F25F42 /* MTRDeviceControllerOverXPC.h */; };
-		5A6FEC9627B5983000F25F42 /* MTRDeviceControllerXPCConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A6FEC9527B5983000F25F42 /* MTRDeviceControllerXPCConnection.m */; };
-		5A6FEC9827B5C6AF00F25F42 /* MTRDeviceOverXPC.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A6FEC9727B5C6AF00F25F42 /* MTRDeviceOverXPC.m */; };
+		5A6FEC9627B5983000F25F42 /* MTRDeviceControllerXPCConnection.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5A6FEC9527B5983000F25F42 /* MTRDeviceControllerXPCConnection.mm */; };
+		5A6FEC9827B5C6AF00F25F42 /* MTRDeviceOverXPC.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5A6FEC9727B5C6AF00F25F42 /* MTRDeviceOverXPC.mm */; };
 		5A6FEC9927B5C88900F25F42 /* MTRDeviceOverXPC.h in Headers */ = {isa = PBXBuildFile; fileRef = 5A6FEC8B27B5609C00F25F42 /* MTRDeviceOverXPC.h */; };
 		5A6FEC9A27B5C89300F25F42 /* MTRDeviceControllerXPCConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 5A6FEC9427B5976200F25F42 /* MTRDeviceControllerXPCConnection.h */; };
 		5A6FEC9D27B5E48900F25F42 /* MTRXPCProtocolTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A6FEC9C27B5E48800F25F42 /* MTRXPCProtocolTests.m */; };
 		5A7947DE27BEC3F500434CF2 /* MTRXPCListenerSampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A7947DD27BEC3F500434CF2 /* MTRXPCListenerSampleTests.m */; };
-		5A7947E427C0129600434CF2 /* MTRDeviceController+XPC.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A7947E327C0129500434CF2 /* MTRDeviceController+XPC.m */; };
+		5A7947E427C0129600434CF2 /* MTRDeviceController+XPC.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5A7947E327C0129500434CF2 /* MTRDeviceController+XPC.mm */; };
 		5A7947E527C0129F00434CF2 /* MTRDeviceController+XPC.h in Headers */ = {isa = PBXBuildFile; fileRef = 5A7947E227C0101200434CF2 /* MTRDeviceController+XPC.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		5A830D6C27CFCF590053B85D /* MTRDeviceControllerOverXPC_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 5A830D6B27CFCF590053B85D /* MTRDeviceControllerOverXPC_Internal.h */; };
 		5ACDDD7A27CD129700EFD68A /* MTRClusterStateCacheContainer.h in Headers */ = {isa = PBXBuildFile; fileRef = 5ACDDD7927CD129700EFD68A /* MTRClusterStateCacheContainer.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -105,7 +110,7 @@
 		88EBF8D027FABDD500686BC1 /* MTRDeviceAttestationDelegateBridge.h in Headers */ = {isa = PBXBuildFile; fileRef = 88EBF8CD27FABDD500686BC1 /* MTRDeviceAttestationDelegateBridge.h */; };
 		991DC0842475F45400C13860 /* MTRDeviceController.h in Headers */ = {isa = PBXBuildFile; fileRef = 991DC0822475F45400C13860 /* MTRDeviceController.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		991DC0892475F47D00C13860 /* MTRDeviceController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 991DC0872475F47D00C13860 /* MTRDeviceController.mm */; };
-		991DC08B247704DC00C13860 /* MTRLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = 991DC08A247704DC00C13860 /* MTRLogging.h */; };
+		991DC08B247704DC00C13860 /* MTRLogging_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 991DC08A247704DC00C13860 /* MTRLogging_Internal.h */; };
 		9956064426420367000C28DE /* MTRSetupPayload_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 9956064326420367000C28DE /* MTRSetupPayload_Internal.h */; };
 		997DED162695343400975E97 /* MTRThreadOperationalDataset.mm in Sources */ = {isa = PBXBuildFile; fileRef = 997DED152695343400975E97 /* MTRThreadOperationalDataset.mm */; };
 		997DED182695344800975E97 /* MTRThreadOperationalDataset.h in Headers */ = {isa = PBXBuildFile; fileRef = 997DED172695344800975E97 /* MTRThreadOperationalDataset.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -113,7 +118,7 @@
 		998F286D26D55E10001846C6 /* MTRKeypair.h in Headers */ = {isa = PBXBuildFile; fileRef = 998F286C26D55E10001846C6 /* MTRKeypair.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		998F286F26D55EC5001846C6 /* MTRP256KeypairBridge.h in Headers */ = {isa = PBXBuildFile; fileRef = 998F286E26D55EC5001846C6 /* MTRP256KeypairBridge.h */; };
 		998F287126D56940001846C6 /* MTRP256KeypairBridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 998F287026D56940001846C6 /* MTRP256KeypairBridge.mm */; };
-		99AECC802798A57F00B6355B /* MTRCommissioningParameters.m in Sources */ = {isa = PBXBuildFile; fileRef = 99AECC7F2798A57E00B6355B /* MTRCommissioningParameters.m */; };
+		99AECC802798A57F00B6355B /* MTRCommissioningParameters.mm in Sources */ = {isa = PBXBuildFile; fileRef = 99AECC7F2798A57E00B6355B /* MTRCommissioningParameters.mm */; };
 		99C65E10267282F1003402F6 /* MTRControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 99C65E0F267282F1003402F6 /* MTRControllerTests.m */; };
 		99D466E12798936D0089A18F /* MTRCommissioningParameters.h in Headers */ = {isa = PBXBuildFile; fileRef = 99D466E02798936D0089A18F /* MTRCommissioningParameters.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		AF1CB86E2874B03B00865A96 /* MTROTAProviderDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = AF1CB86D2874B03B00865A96 /* MTROTAProviderDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -121,7 +126,7 @@
 		AF5F90FF2878D351005503FA /* MTROTAProviderDelegateBridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = AF5F90FE2878D351005503FA /* MTROTAProviderDelegateBridge.mm */; };
 		B20252972459E34F00F97062 /* Matter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B202528D2459E34F00F97062 /* Matter.framework */; };
 		B289D4212639C0D300D4E314 /* MTROnboardingPayloadParser.h in Headers */ = {isa = PBXBuildFile; fileRef = B289D41F2639C0D300D4E314 /* MTROnboardingPayloadParser.h */; settings = {ATTRIBUTES = (Public, ); }; };
-		B289D4222639C0D300D4E314 /* MTROnboardingPayloadParser.m in Sources */ = {isa = PBXBuildFile; fileRef = B289D4202639C0D300D4E314 /* MTROnboardingPayloadParser.m */; };
+		B289D4222639C0D300D4E314 /* MTROnboardingPayloadParser.mm in Sources */ = {isa = PBXBuildFile; fileRef = B289D4202639C0D300D4E314 /* MTROnboardingPayloadParser.mm */; };
 		B2E0D7B1245B0B5C003C5B48 /* Matter.h in Headers */ = {isa = PBXBuildFile; fileRef = B2E0D7A8245B0B5C003C5B48 /* Matter.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		B2E0D7B2245B0B5C003C5B48 /* MTRManualSetupPayloadParser.h in Headers */ = {isa = PBXBuildFile; fileRef = B2E0D7A9245B0B5C003C5B48 /* MTRManualSetupPayloadParser.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		B2E0D7B3245B0B5C003C5B48 /* MTRError.mm in Sources */ = {isa = PBXBuildFile; fileRef = B2E0D7AA245B0B5C003C5B48 /* MTRError.mm */; };
@@ -146,6 +151,20 @@
 		};
 /* End PBXContainerItemProxy section */
 
+/* Begin PBXCopyFilesBuildPhase section */
+		3D69868429383083007314E7 /* Copy Logging Preferences */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 8;
+			dstPath = "$(SYSTEM_LIBRARY_DIR)/Preferences/Logging/Subsystems";
+			dstSubfolderSpec = 0;
+			files = (
+				3D69868529383096007314E7 /* com.csa.matter.plist in Copy Logging Preferences */,
+			);
+			name = "Copy Logging Preferences";
+			runOnlyForDeploymentPostprocessing = 1;
+		};
+/* End PBXCopyFilesBuildPhase section */
+
 /* Begin PBXFileReference section */
 		1E748B3828941A44008A1BE8 /* MTRTestOTAProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTRTestOTAProvider.m; sourceTree = "<group>"; };
 		1E748B3928941A45008A1BE8 /* MTRTestOTAProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRTestOTAProvider.h; sourceTree = "<group>"; };
@@ -174,10 +193,15 @@
 		2CB7163E252F731E0026E2BB /* MTRDeviceControllerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRDeviceControllerDelegate.h; sourceTree = "<group>"; };
 		2FD775542695557E00FF4B12 /* error-mapping.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "error-mapping.cpp"; path = "../../../app/util/error-mapping.cpp"; sourceTree = "<group>"; };
 		3CF134A6289D8AD90017A19E /* MTRCSRInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRCSRInfo.h; sourceTree = "<group>"; };
-		3CF134A8289D8D800017A19E /* MTRCSRInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MTRCSRInfo.m; sourceTree = "<group>"; };
+		3CF134A8289D8D800017A19E /* MTRCSRInfo.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRCSRInfo.mm; sourceTree = "<group>"; };
 		3CF134AA289D8DF70017A19E /* MTRAttestationInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRAttestationInfo.h; sourceTree = "<group>"; };
-		3CF134AC289D8E570017A19E /* MTRAttestationInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MTRAttestationInfo.m; sourceTree = "<group>"; };
+		3CF134AC289D8E570017A19E /* MTRAttestationInfo.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRAttestationInfo.mm; sourceTree = "<group>"; };
 		3CF134AE289D90FF0017A19E /* MTRNOCChainIssuer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRNOCChainIssuer.h; sourceTree = "<group>"; };
+		3D69868029382EF4007314E7 /* com.csa.matter.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.csa.matter.plist; sourceTree = "<group>"; };
+		3DECCB6D29347D2C00585AEC /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.1.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; };
+		3DECCB6F2934AC1C00585AEC /* MTRLogging.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRLogging.h; sourceTree = "<group>"; };
+		3DECCB712934AFE200585AEC /* MTRLogging.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRLogging.mm; sourceTree = "<group>"; };
+		3DECCB732934C21B00585AEC /* MTRDefines.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRDefines.h; sourceTree = "<group>"; };
 		5112F605287CD2C100B827E7 /* privilege-storage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "privilege-storage.cpp"; path = "../../../app/util/privilege-storage.cpp"; sourceTree = "<group>"; };
 		511913F928C100EF009235E9 /* MTRBaseSubscriptionCallback.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRBaseSubscriptionCallback.mm; sourceTree = "<group>"; };
 		511913FA28C100EF009235E9 /* MTRBaseSubscriptionCallback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRBaseSubscriptionCallback.h; sourceTree = "<group>"; };
@@ -191,8 +215,8 @@
 		5143041F2914CED9004DC7FE /* generic-callback-stubs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "generic-callback-stubs.cpp"; path = "../../../app/util/generic-callback-stubs.cpp"; sourceTree = "<group>"; };
 		51431AF827D2973E008A7943 /* MTRIMDispatch.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRIMDispatch.mm; sourceTree = "<group>"; };
 		51431AFA27D29CA4008A7943 /* ota-provider.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "ota-provider.cpp"; path = "../../../app/clusters/ota-provider/ota-provider.cpp"; sourceTree = "<group>"; };
-		515C1C6D284F9FFB00A48F0C /* MTRMemory.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRMemory.mm; sourceTree = "<group>"; };
-		515C1C6E284F9FFB00A48F0C /* MTRMemory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRMemory.h; sourceTree = "<group>"; };
+		515C1C6D284F9FFB00A48F0C /* MTRFramework.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRFramework.mm; sourceTree = "<group>"; };
+		515C1C6E284F9FFB00A48F0C /* MTRFramework.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRFramework.h; sourceTree = "<group>"; };
 		51669AEF2913204400F4AA36 /* MTRBackwardsCompatTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTRBackwardsCompatTests.m; sourceTree = "<group>"; };
 		517BF3EE282B62B800A8B7DB /* MTRCertificates.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRCertificates.h; sourceTree = "<group>"; };
 		517BF3EF282B62B800A8B7DB /* MTRCertificates.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRCertificates.mm; sourceTree = "<group>"; };
@@ -213,14 +237,14 @@
 		5A60370727EA1FF60020DB79 /* MTRClusterStateCacheContainer+XPC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MTRClusterStateCacheContainer+XPC.h"; sourceTree = "<group>"; };
 		5A6FEC8B27B5609C00F25F42 /* MTRDeviceOverXPC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRDeviceOverXPC.h; sourceTree = "<group>"; };
 		5A6FEC8D27B5624E00F25F42 /* MTRDeviceControllerOverXPC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRDeviceControllerOverXPC.h; sourceTree = "<group>"; };
-		5A6FEC8F27B563D900F25F42 /* MTRDeviceControllerOverXPC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MTRDeviceControllerOverXPC.m; sourceTree = "<group>"; };
+		5A6FEC8F27B563D900F25F42 /* MTRDeviceControllerOverXPC.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRDeviceControllerOverXPC.mm; sourceTree = "<group>"; };
 		5A6FEC9427B5976200F25F42 /* MTRDeviceControllerXPCConnection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRDeviceControllerXPCConnection.h; sourceTree = "<group>"; };
-		5A6FEC9527B5983000F25F42 /* MTRDeviceControllerXPCConnection.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MTRDeviceControllerXPCConnection.m; sourceTree = "<group>"; };
-		5A6FEC9727B5C6AF00F25F42 /* MTRDeviceOverXPC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MTRDeviceOverXPC.m; sourceTree = "<group>"; };
+		5A6FEC9527B5983000F25F42 /* MTRDeviceControllerXPCConnection.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRDeviceControllerXPCConnection.mm; sourceTree = "<group>"; };
+		5A6FEC9727B5C6AF00F25F42 /* MTRDeviceOverXPC.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRDeviceOverXPC.mm; sourceTree = "<group>"; };
 		5A6FEC9C27B5E48800F25F42 /* MTRXPCProtocolTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MTRXPCProtocolTests.m; sourceTree = "<group>"; };
 		5A7947DD27BEC3F500434CF2 /* MTRXPCListenerSampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MTRXPCListenerSampleTests.m; sourceTree = "<group>"; };
 		5A7947E227C0101200434CF2 /* MTRDeviceController+XPC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MTRDeviceController+XPC.h"; sourceTree = "<group>"; };
-		5A7947E327C0129500434CF2 /* MTRDeviceController+XPC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "MTRDeviceController+XPC.m"; sourceTree = "<group>"; };
+		5A7947E327C0129500434CF2 /* MTRDeviceController+XPC.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = "MTRDeviceController+XPC.mm"; sourceTree = "<group>"; };
 		5A830D6B27CFCF590053B85D /* MTRDeviceControllerOverXPC_Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRDeviceControllerOverXPC_Internal.h; sourceTree = "<group>"; };
 		5ACDDD7927CD129700EFD68A /* MTRClusterStateCacheContainer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRClusterStateCacheContainer.h; sourceTree = "<group>"; };
 		5ACDDD7B27CD14AF00EFD68A /* MTRClusterStateCacheContainer_Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRClusterStateCacheContainer_Internal.h; sourceTree = "<group>"; };
@@ -246,7 +270,7 @@
 		88EBF8CD27FABDD500686BC1 /* MTRDeviceAttestationDelegateBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRDeviceAttestationDelegateBridge.h; sourceTree = "<group>"; };
 		991DC0822475F45400C13860 /* MTRDeviceController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRDeviceController.h; sourceTree = "<group>"; };
 		991DC0872475F47D00C13860 /* MTRDeviceController.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRDeviceController.mm; sourceTree = "<group>"; };
-		991DC08A247704DC00C13860 /* MTRLogging.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRLogging.h; sourceTree = "<group>"; };
+		991DC08A247704DC00C13860 /* MTRLogging_Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRLogging_Internal.h; sourceTree = "<group>"; };
 		9956064326420367000C28DE /* MTRSetupPayload_Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRSetupPayload_Internal.h; sourceTree = "<group>"; };
 		997DED152695343400975E97 /* MTRThreadOperationalDataset.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRThreadOperationalDataset.mm; sourceTree = "<group>"; };
 		997DED172695344800975E97 /* MTRThreadOperationalDataset.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRThreadOperationalDataset.h; sourceTree = "<group>"; };
@@ -254,7 +278,7 @@
 		998F286C26D55E10001846C6 /* MTRKeypair.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRKeypair.h; sourceTree = "<group>"; };
 		998F286E26D55EC5001846C6 /* MTRP256KeypairBridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRP256KeypairBridge.h; sourceTree = "<group>"; };
 		998F287026D56940001846C6 /* MTRP256KeypairBridge.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRP256KeypairBridge.mm; sourceTree = "<group>"; };
-		99AECC7F2798A57E00B6355B /* MTRCommissioningParameters.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MTRCommissioningParameters.m; sourceTree = "<group>"; };
+		99AECC7F2798A57E00B6355B /* MTRCommissioningParameters.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRCommissioningParameters.mm; sourceTree = "<group>"; };
 		99C65E0F267282F1003402F6 /* MTRControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MTRControllerTests.m; sourceTree = "<group>"; };
 		99D466E02798936D0089A18F /* MTRCommissioningParameters.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRCommissioningParameters.h; sourceTree = "<group>"; };
 		AF1CB86D2874B03B00865A96 /* MTROTAProviderDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTROTAProviderDelegate.h; sourceTree = "<group>"; };
@@ -265,7 +289,7 @@
 		B20252962459E34F00F97062 /* MatterTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MatterTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
 		B202529D2459E34F00F97062 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 		B289D41F2639C0D300D4E314 /* MTROnboardingPayloadParser.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTROnboardingPayloadParser.h; sourceTree = "<group>"; };
-		B289D4202639C0D300D4E314 /* MTROnboardingPayloadParser.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MTROnboardingPayloadParser.m; sourceTree = "<group>"; };
+		B289D4202639C0D300D4E314 /* MTROnboardingPayloadParser.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MTROnboardingPayloadParser.mm; sourceTree = "<group>"; };
 		B2E0D7A8245B0B5C003C5B48 /* Matter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Matter.h; sourceTree = "<group>"; };
 		B2E0D7A9245B0B5C003C5B48 /* MTRManualSetupPayloadParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRManualSetupPayloadParser.h; sourceTree = "<group>"; };
 		B2E0D7AA245B0B5C003C5B48 /* MTRError.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRError.mm; sourceTree = "<group>"; };
@@ -289,6 +313,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				3DECCB6E29347D2D00585AEC /* Security.framework in Frameworks */,
 				BA09EB43247477BA00605257 /* libCHIP.a in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -336,6 +361,22 @@
 			name = CHIPGeneratedFiles;
 			sourceTree = "<group>";
 		};
+		3D69867E29382E58007314E7 /* Resources */ = {
+			isa = PBXGroup;
+			children = (
+				3D69867F29382EAD007314E7 /* Logging */,
+			);
+			path = Resources;
+			sourceTree = "<group>";
+		};
+		3D69867F29382EAD007314E7 /* Logging */ = {
+			isa = PBXGroup;
+			children = (
+				3D69868029382EF4007314E7 /* com.csa.matter.plist */,
+			);
+			path = Logging;
+			sourceTree = "<group>";
+		};
 		B20252832459E34F00F97062 = {
 			isa = PBXGroup;
 			children = (
@@ -359,6 +400,7 @@
 		B202528F2459E34F00F97062 /* CHIP */ = {
 			isa = PBXGroup;
 			children = (
+				3D69867E29382E58007314E7 /* Resources */,
 				1EDCE543289049A100E41EC9 /* MTROTAHeader.h */,
 				1EDCE544289049A100E41EC9 /* MTROTAHeader.mm */,
 				27A53C1527FBC6920053F131 /* MTRAttestationTrustStoreBridge.h */,
@@ -385,6 +427,7 @@
 				2C222ADE255C811800E446B9 /* MTRBaseDevice_Internal.h */,
 				2C222ACE255C620600E446B9 /* MTRBaseDevice.h */,
 				2C222ACF255C620600E446B9 /* MTRBaseDevice.mm */,
+				3DECCB732934C21B00585AEC /* MTRDefines.h */,
 				7596A84A287636C1004DAE0E /* MTRDevice_Internal.h */,
 				7596A84228762729004DAE0E /* MTRDevice.h */,
 				7596A84328762729004DAE0E /* MTRDevice.mm */,
@@ -401,7 +444,7 @@
 				2C8C8FBD253E0C2100797F05 /* MTRPersistentStorageDelegateBridge.h */,
 				2C8C8FBF253E0C2100797F05 /* MTRPersistentStorageDelegateBridge.mm */,
 				99D466E02798936D0089A18F /* MTRCommissioningParameters.h */,
-				99AECC7F2798A57E00B6355B /* MTRCommissioningParameters.m */,
+				99AECC7F2798A57E00B6355B /* MTRCommissioningParameters.mm */,
 				2CB7163E252F731E0026E2BB /* MTRDeviceControllerDelegate.h */,
 				2CB71638252E8A7B0026E2BB /* MTRDeviceControllerDelegateBridge.h */,
 				2CB71639252E8A7B0026E2BB /* MTRDeviceControllerDelegateBridge.mm */,
@@ -412,9 +455,11 @@
 				B2E0D7AB245B0B5C003C5B48 /* MTRError_Internal.h */,
 				5129BCFC26A9EE3300122DDF /* MTRError.h */,
 				B2E0D7AA245B0B5C003C5B48 /* MTRError.mm */,
-				991DC08A247704DC00C13860 /* MTRLogging.h */,
+				3DECCB6F2934AC1C00585AEC /* MTRLogging.h */,
+				991DC08A247704DC00C13860 /* MTRLogging_Internal.h */,
+				3DECCB712934AFE200585AEC /* MTRLogging.mm */,
 				B289D41F2639C0D300D4E314 /* MTROnboardingPayloadParser.h */,
-				B289D4202639C0D300D4E314 /* MTROnboardingPayloadParser.m */,
+				B289D4202639C0D300D4E314 /* MTROnboardingPayloadParser.mm */,
 				B2E0D7A9245B0B5C003C5B48 /* MTRManualSetupPayloadParser.h */,
 				B2E0D7AD245B0B5C003C5B48 /* MTRManualSetupPayloadParser.mm */,
 				B2E0D7AC245B0B5C003C5B48 /* MTRQRCodeSetupPayloadParser.h */,
@@ -434,24 +479,24 @@
 				5A7947E227C0101200434CF2 /* MTRDeviceController+XPC.h */,
 				517BF3EE282B62B800A8B7DB /* MTRCertificates.h */,
 				517BF3EF282B62B800A8B7DB /* MTRCertificates.mm */,
-				515C1C6E284F9FFB00A48F0C /* MTRMemory.h */,
-				515C1C6D284F9FFB00A48F0C /* MTRMemory.mm */,
-				5A7947E327C0129500434CF2 /* MTRDeviceController+XPC.m */,
+				515C1C6E284F9FFB00A48F0C /* MTRFramework.h */,
+				515C1C6D284F9FFB00A48F0C /* MTRFramework.mm */,
+				5A7947E327C0129500434CF2 /* MTRDeviceController+XPC.mm */,
 				B20252912459E34F00F97062 /* Info.plist */,
 				998F286C26D55E10001846C6 /* MTRKeypair.h */,
 				998F286E26D55EC5001846C6 /* MTRP256KeypairBridge.h */,
 				998F287026D56940001846C6 /* MTRP256KeypairBridge.mm */,
 				5A6FEC8B27B5609C00F25F42 /* MTRDeviceOverXPC.h */,
-				5A6FEC9727B5C6AF00F25F42 /* MTRDeviceOverXPC.m */,
+				5A6FEC9727B5C6AF00F25F42 /* MTRDeviceOverXPC.mm */,
 				5A6FEC8D27B5624E00F25F42 /* MTRDeviceControllerOverXPC.h */,
 				5A830D6B27CFCF590053B85D /* MTRDeviceControllerOverXPC_Internal.h */,
-				5A6FEC8F27B563D900F25F42 /* MTRDeviceControllerOverXPC.m */,
+				5A6FEC8F27B563D900F25F42 /* MTRDeviceControllerOverXPC.mm */,
 				5A6FEC9427B5976200F25F42 /* MTRDeviceControllerXPCConnection.h */,
-				5A6FEC9527B5983000F25F42 /* MTRDeviceControllerXPCConnection.m */,
+				5A6FEC9527B5983000F25F42 /* MTRDeviceControllerXPCConnection.mm */,
 				3CF134A6289D8AD90017A19E /* MTRCSRInfo.h */,
-				3CF134A8289D8D800017A19E /* MTRCSRInfo.m */,
+				3CF134A8289D8D800017A19E /* MTRCSRInfo.mm */,
 				3CF134AA289D8DF70017A19E /* MTRAttestationInfo.h */,
-				3CF134AC289D8E570017A19E /* MTRAttestationInfo.m */,
+				3CF134AC289D8E570017A19E /* MTRAttestationInfo.mm */,
 				3CF134AE289D90FF0017A19E /* MTRNOCChainIssuer.h */,
 				511913FA28C100EF009235E9 /* MTRBaseSubscriptionCallback.h */,
 				511913F928C100EF009235E9 /* MTRBaseSubscriptionCallback.mm */,
@@ -488,6 +533,7 @@
 		BA09EB3E2474762900605257 /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
+				3DECCB6D29347D2C00585AEC /* Security.framework */,
 				BA09EB3F2474762900605257 /* libCHIP.a */,
 			);
 			name = Frameworks;
@@ -514,7 +560,7 @@
 				7596A85728788557004DAE0E /* MTRClusters.h in Headers */,
 				99D466E12798936D0089A18F /* MTRCommissioningParameters.h in Headers */,
 				5136661528067D550025EDAE /* MTRDeviceControllerFactory_Internal.h in Headers */,
-				515C1C70284F9FFB00A48F0C /* MTRMemory.h in Headers */,
+				515C1C70284F9FFB00A48F0C /* MTRFramework.h in Headers */,
 				7534F12928BFF20300390851 /* MTRDeviceAttestationDelegate_Internal.h in Headers */,
 				D4772A46285AE98400383630 /* MTRClusterConstants.h in Headers */,
 				B289D4212639C0D300D4E314 /* MTROnboardingPayloadParser.h in Headers */,
@@ -551,15 +597,17 @@
 				AF1CB8702874B04C00865A96 /* MTROTAProviderDelegateBridge.h in Headers */,
 				B2E0D7B5245B0B5C003C5B48 /* MTRQRCodeSetupPayloadParser.h in Headers */,
 				1EC4CE6425CC276600D7304F /* MTRBaseClusters.h in Headers */,
+				3DECCB742934C21B00585AEC /* MTRDefines.h in Headers */,
 				2C5EEEF6268A85C400CAE3D3 /* MTRDeviceConnectionBridge.h in Headers */,
 				2C8C8FC0253E0C2100797F05 /* MTRPersistentStorageDelegateBridge.h in Headers */,
 				51E4D121291D0EB400C8C535 /* MTRBaseClustersCpp_Internal.h in Headers */,
 				51E51FC0282AD37A00FC978D /* MTRDeviceControllerStartupParams_Internal.h in Headers */,
+				3DECCB702934AECD00585AEC /* MTRLogging.h in Headers */,
 				998F286F26D55EC5001846C6 /* MTRP256KeypairBridge.h in Headers */,
 				2C222ADF255C811800E446B9 /* MTRBaseDevice_Internal.h in Headers */,
 				511913FC28C100EF009235E9 /* MTRBaseSubscriptionCallback.h in Headers */,
 				51E0310027EA20D20083DC9C /* MTRControllerAccessControl.h in Headers */,
-				991DC08B247704DC00C13860 /* MTRLogging.h in Headers */,
+				991DC08B247704DC00C13860 /* MTRLogging_Internal.h in Headers */,
 				7596A84828762783004DAE0E /* MTRAsyncCallbackWorkQueue.h in Headers */,
 				5A7947E527C0129F00434CF2 /* MTRDeviceController+XPC.h in Headers */,
 				B2E0D7B4245B0B5C003C5B48 /* MTRError_Internal.h in Headers */,
@@ -579,6 +627,7 @@
 				B20252892459E34F00F97062 /* Sources */,
 				B202528A2459E34F00F97062 /* Frameworks */,
 				B202528B2459E34F00F97062 /* Resources */,
+				3D69868429383083007314E7 /* Copy Logging Preferences */,
 			);
 			buildRules = (
 			);
@@ -689,10 +738,10 @@
 			buildActionMask = 2147483647;
 			files = (
 				2C8C8FC2253E0C2100797F05 /* MTRPersistentStorageDelegateBridge.mm in Sources */,
-				99AECC802798A57F00B6355B /* MTRCommissioningParameters.m in Sources */,
+				99AECC802798A57F00B6355B /* MTRCommissioningParameters.mm in Sources */,
 				2CB7163C252E8A7C0026E2BB /* MTRDeviceControllerDelegateBridge.mm in Sources */,
 				997DED162695343400975E97 /* MTRThreadOperationalDataset.mm in Sources */,
-				515C1C6F284F9FFB00A48F0C /* MTRMemory.mm in Sources */,
+				515C1C6F284F9FFB00A48F0C /* MTRFramework.mm in Sources */,
 				27A53C1827FBC6920053F131 /* MTRAttestationTrustStoreBridge.mm in Sources */,
 				998F287126D56940001846C6 /* MTRP256KeypairBridge.mm in Sources */,
 				5136661428067D550025EDAE /* MTRDeviceControllerFactory.mm in Sources */,
@@ -703,7 +752,7 @@
 				51B22C262740CB32008D5055 /* MTRStructsObjc.mm in Sources */,
 				2C222AD1255C620600E446B9 /* MTRBaseDevice.mm in Sources */,
 				1EC3238D271999E2002A8BF0 /* cluster-objects.cpp in Sources */,
-				3CF134A9289D8D800017A19E /* MTRCSRInfo.m in Sources */,
+				3CF134A9289D8D800017A19E /* MTRCSRInfo.mm in Sources */,
 				991DC0892475F47D00C13860 /* MTRDeviceController.mm in Sources */,
 				B2E0D7B7245B0B5C003C5B48 /* MTRQRCodeSetupPayloadParser.mm in Sources */,
 				514304202914CED9004DC7FE /* generic-callback-stubs.cpp in Sources */,
@@ -715,16 +764,16 @@
 				51E51FC1282AD37A00FC978D /* MTRDeviceControllerStartupParams.mm in Sources */,
 				1ED276E026C57CF000547A89 /* MTRCallbackBridge.mm in Sources */,
 				517BF3F1282B62B800A8B7DB /* MTRCertificates.mm in Sources */,
-				5A6FEC9627B5983000F25F42 /* MTRDeviceControllerXPCConnection.m in Sources */,
+				5A6FEC9627B5983000F25F42 /* MTRDeviceControllerXPCConnection.mm in Sources */,
 				511913FB28C100EF009235E9 /* MTRBaseSubscriptionCallback.mm in Sources */,
 				5ACDDD7D27CD16D200EFD68A /* MTRClusterStateCacheContainer.mm in Sources */,
 				513DDB8A2761F6F900DAA01A /* MTRAttributeTLVValueDecoder.mm in Sources */,
 				2FD775552695557E00FF4B12 /* error-mapping.cpp in Sources */,
-				5A7947E427C0129600434CF2 /* MTRDeviceController+XPC.m in Sources */,
-				5A6FEC9027B563D900F25F42 /* MTRDeviceControllerOverXPC.m in Sources */,
-				B289D4222639C0D300D4E314 /* MTROnboardingPayloadParser.m in Sources */,
+				5A7947E427C0129600434CF2 /* MTRDeviceController+XPC.mm in Sources */,
+				5A6FEC9027B563D900F25F42 /* MTRDeviceControllerOverXPC.mm in Sources */,
+				B289D4222639C0D300D4E314 /* MTROnboardingPayloadParser.mm in Sources */,
 				5112F606287CD2C100B827E7 /* privilege-storage.cpp in Sources */,
-				3CF134AD289D8E570017A19E /* MTRAttestationInfo.m in Sources */,
+				3CF134AD289D8E570017A19E /* MTRAttestationInfo.mm in Sources */,
 				2C1B027A2641DB4E00780EF1 /* MTROperationalCredentialsDelegate.mm in Sources */,
 				7560FD1C27FBBD3F005E85B3 /* MTREventTLVValueDecoder.mm in Sources */,
 				7596A84928762783004DAE0E /* MTRAsyncCallbackWorkQueue.mm in Sources */,
@@ -732,9 +781,10 @@
 				B2E0D7B6245B0B5C003C5B48 /* MTRManualSetupPayloadParser.mm in Sources */,
 				7596A85528788557004DAE0E /* MTRClusters.mm in Sources */,
 				88EBF8CF27FABDD500686BC1 /* MTRDeviceAttestationDelegateBridge.mm in Sources */,
-				5A6FEC9827B5C6AF00F25F42 /* MTRDeviceOverXPC.m in Sources */,
+				5A6FEC9827B5C6AF00F25F42 /* MTRDeviceOverXPC.mm in Sources */,
 				51431AF927D2973E008A7943 /* MTRIMDispatch.mm in Sources */,
 				51431AFB27D29CA4008A7943 /* ota-provider.cpp in Sources */,
+				3DECCB722934AFE200585AEC /* MTRLogging.mm in Sources */,
 				7596A84528762729004DAE0E /* MTRDevice.mm in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -826,6 +876,12 @@
 				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
 				MTL_FAST_MATH = YES;
 				ONLY_ACTIVE_ARCH = YES;
+				OTHER_CFLAGS = (
+					"-Wformat",
+					"-Wformat-nonliteral",
+					"-Wformat-security",
+					"-Wconversion",
+				);
 				OTHER_LDFLAGS = "-Wl,-unexported_symbol,\"__Z*\"";
 				SDKROOT = iphoneos;
 				SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos appletvos appletvsimulator watchos watchsimulator";
@@ -872,11 +928,6 @@
 				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
 				IPHONEOS_DEPLOYMENT_TARGET = 13.4;
 				LIBRARY_SEARCH_PATHS = "$(TEMP_DIR)/out/lib";
-				OTHER_CFLAGS = (
-					"-Wformat",
-					"-Wformat-nonliteral",
-					"-Wformat-security",
-				);
 				OTHER_LDFLAGS = "";
 				"OTHER_LDFLAGS[sdk=*]" = (
 					"-framework",
@@ -975,6 +1026,12 @@
 				MTL_ENABLE_DEBUG_INFO = NO;
 				MTL_FAST_MATH = YES;
 				ONLY_ACTIVE_ARCH = YES;
+				OTHER_CFLAGS = (
+					"-Wformat",
+					"-Wformat-nonliteral",
+					"-Wformat-security",
+					"-Wconversion",
+				);
 				OTHER_LDFLAGS = "-Wl,-unexported_symbol,\"__Z*\"";
 				SDKROOT = iphoneos;
 				SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos appletvos appletvsimulator watchos watchsimulator";
@@ -1022,11 +1079,6 @@
 				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
 				IPHONEOS_DEPLOYMENT_TARGET = 13.4;
 				LIBRARY_SEARCH_PATHS = "$(TEMP_DIR)/out/lib";
-				OTHER_CFLAGS = (
-					"-Wformat",
-					"-Wformat-nonliteral",
-					"-Wformat-security",
-				);
 				OTHER_LDFLAGS = "";
 				"OTHER_LDFLAGS[sdk=*]" = (
 					"-framework",
diff --git a/src/lib/core/CHIPConfig.h b/src/lib/core/CHIPConfig.h
index b84fa02..aaa28d0 100644
--- a/src/lib/core/CHIPConfig.h
+++ b/src/lib/core/CHIPConfig.h
@@ -375,6 +375,16 @@
 #endif // CHIP_AUTOMATION_LOGGING
 
 /**
+ *  @def CHIP_LOG_FILTERING
+ *
+ *  @brief
+ *    If asserted (1), enable runtime log level configuration.
+ */
+#ifndef CHIP_LOG_FILTERING
+#define CHIP_LOG_FILTERING 1
+#endif
+
+/**
  * CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE
  *
  * The maximum size (in bytes) of a log message
diff --git a/src/lib/support/BUILD.gn b/src/lib/support/BUILD.gn
index 2f86189..d006b42 100644
--- a/src/lib/support/BUILD.gn
+++ b/src/lib/support/BUILD.gn
@@ -66,8 +66,11 @@
   sources = [ "logging/Constants.h" ]
 }
 
-source_set("enforce_format") {
-  sources = [ "EnforceFormat.h" ]
+source_set("attributes") {
+  sources = [
+    "DLLUtil.h",
+    "EnforceFormat.h",
+  ]
 }
 
 source_set("chip_version_header") {
@@ -165,8 +168,8 @@
   cflags = [ "-Wconversion" ]
 
   public_deps = [
+    ":attributes",
     ":chip_version_header",
-    ":enforce_format",
     ":logging_constants",
     "${chip_root}/src/lib/core:chip_config_header",
     "${chip_root}/src/platform:platform_buildconfig",
@@ -188,6 +191,10 @@
     public_deps += [ "${chip_root}/src/platform/logging:android" ]
   }
 
+  if (current_os == "mac" || current_os == "ios") {
+    public_deps += [ "${chip_root}/src/platform/Darwin:logging" ]
+  }
+
   public_configs = [
     "${chip_root}/src:includes",
     "${chip_root}/src/system:system_config",
diff --git a/src/lib/support/CodeUtils.h b/src/lib/support/CodeUtils.h
index ae61f52..3b754e0 100644
--- a/src/lib/support/CodeUtils.h
+++ b/src/lib/support/CodeUtils.h
@@ -254,11 +254,12 @@
  *
  *  Example usage:
  *
- * @code
+ *  @code
  *    VerifyOrReturn(param != nullptr, LogError("param is nullptr"));
  *  @endcode
  *
  *  @param[in]  expr        A Boolean expression to be evaluated.
+ *  @param[in]  ...         Statements to execute before returning. Optional.
  */
 #define VerifyOrReturn(expr, ...)                                                                                                  \
     do                                                                                                                             \
@@ -271,7 +272,7 @@
     } while (false)
 
 /**
- *  @def VerifyOrReturnError(expr, code)
+ *  @def VerifyOrReturnError(expr, code, ...)
  *
  *  @brief
  *    Returns a specified error code if expression evaluates to false
@@ -284,11 +285,12 @@
  *
  *  @param[in]  expr        A Boolean expression to be evaluated.
  *  @param[in]  code        A value to return if @a expr is false.
+ *  @param[in]  ...         Statements to execute before returning. Optional.
  */
-#define VerifyOrReturnError(expr, code) VerifyOrReturnValue(expr, code)
+#define VerifyOrReturnError(expr, code, ...) VerifyOrReturnValue(expr, code, ##__VA_ARGS__)
 
 /**
- *  @def VerifyOrReturnValue(expr, value)
+ *  @def VerifyOrReturnValue(expr, value, ...)
  *
  *  @brief
  *    Returns a specified value if expression evaluates to false
@@ -301,12 +303,14 @@
  *
  *  @param[in]  expr        A Boolean expression to be evaluated.
  *  @param[in]  value       A value to return if @a expr is false.
+ *  @param[in]  ...         Statements to execute before returning. Optional.
  */
-#define VerifyOrReturnValue(expr, value)                                                                                           \
+#define VerifyOrReturnValue(expr, value, ...)                                                                                      \
     do                                                                                                                             \
     {                                                                                                                              \
         if (!(expr))                                                                                                               \
         {                                                                                                                          \
+            __VA_ARGS__;                                                                                                           \
             return (value);                                                                                                        \
         }                                                                                                                          \
     } while (false)
@@ -468,9 +472,7 @@
  *  }
  *  @endcode
  *
- *  @param[in]  ...         An optional expression or block to execute
- *                          when the assertion fails.
- *
+ *  @param[in]  ...         Statements to execute. Optional.
  */
 // clang-format off
 #define ExitNow(...)                                                   \
@@ -622,6 +624,7 @@
  *  @endcode
  *
  *  @param[in]  expr        A Boolean expression to be evaluated.
+ *  @param[in]  ...         Statements to execute.
  */
 #define VerifyOrDo(expr, ...)                                                                                                      \
     do                                                                                                                             \
diff --git a/src/lib/support/logging/CHIPLogging.cpp b/src/lib/support/logging/CHIPLogging.cpp
index a374893..ca04f60 100644
--- a/src/lib/support/logging/CHIPLogging.cpp
+++ b/src/lib/support/logging/CHIPLogging.cpp
@@ -28,9 +28,10 @@
 #include <lib/core/CHIPCore.h>
 #include <lib/support/CHIPMem.h>
 #include <lib/support/CodeUtils.h>
-#include <lib/support/DLLUtil.h>
 #include <lib/support/Span.h>
 
+#include <platform/logging/LogV.h>
+
 #include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
@@ -69,70 +70,56 @@
 std::atomic<LogRedirectCallback_t> sLogRedirectCallback{ nullptr };
 
 /*
- * Array of strings containing the names for each of the chip log
- * modules.
+ * Array of strings containing the names for each of the chip log modules.
  *
- * NOTE: The names must be in the order defined in the LogModule
- *       enumeration. Each name must be a fixed number of characters
- *       long (chip::Logging::kMaxModuleNameLen) padded with nulls as
- *       necessary.
- *
+ * NOTE: The names must be in the order defined in the LogModule enumeration.
  */
-const char ModuleNames[] = "-\0\0" // None
-                           "IN\0"  // Inet
-                           "BLE"   // BLE
-                           "ML\0"  // MessageLayer
-                           "SM\0"  // SecurityManager
-                           "EM\0"  // ExchangeManager
-                           "TLV"   // TLV
-                           "ASN"   // ASN1
-                           "CR\0"  // Crypto
-                           "CTL"   // Controller
-                           "AL\0"  // Alarm
-                           "SC\0"  // SecureChannel
-                           "BDX"   // BulkDataTransfer
-                           "DMG"   // DataManagement
-                           "DC\0"  // DeviceControl
-                           "DD\0"  // DeviceDescription
-                           "ECH"   // Echo
-                           "FP\0"  // FabricProvisioning
-                           "NP\0"  // NetworkProvisioning
-                           "SD\0"  // ServiceDirectory
-                           "SP\0"  // ServiceProvisioning
-                           "SWU"   // SoftwareUpdate
-                           "FS\0"  // FailSafe
-                           "TS\0"  // TimeService
-                           "HB\0"  // Heartbeat
-                           "CSL"   // chipSystemLayer
-                           "EVL"   // Event Logging
-                           "SPT"   // Support
-                           "TOO"   // chipTool
-                           "ZCL"   // Zcl
-                           "SH\0"  // Shell
-                           "DL\0"  // DeviceLayer
-                           "SPL"   // SetupPayload
-                           "SVR"   // AppServer
-                           "DIS"   // Discovery
-                           "IM\0"  // InteractionModel
-                           "TST"   // Test
-                           "OSS"   // OperationalSessionSetup
-                           "ATM"   // Automation
-                           "CSM"   // CASESessionManager
-    ;
+static const char ModuleNames[kLogModule_Max][kMaxModuleNameLen + 1] = {
+    "-",   // None
+    "IN",  // Inet
+    "BLE", // BLE
+    "ML",  // MessageLayer
+    "SM",  // SecurityManager
+    "EM",  // ExchangeManager
+    "TLV", // TLV
+    "ASN", // ASN1
+    "CR",  // Crypto
+    "CTL", // Controller
+    "AL",  // Alarm
+    "SC",  // SecureChannel
+    "BDX", // BulkDataTransfer
+    "DMG", // DataManagement
+    "DC",  // DeviceControl
+    "DD",  // DeviceDescription
+    "ECH", // Echo
+    "FP",  // FabricProvisioning
+    "NP",  // NetworkProvisioning
+    "SD",  // ServiceDirectory
+    "SP",  // ServiceProvisioning
+    "SWU", // SoftwareUpdate
+    "FS",  // FailSafe
+    "TS",  // TimeService
+    "HB",  // Heartbeat
+    "CSL", // chipSystemLayer
+    "EVL", // Event Logging
+    "SPT", // Support
+    "TOO", // chipTool
+    "ZCL", // Zcl
+    "SH",  // Shell
+    "DL",  // DeviceLayer
+    "SPL", // SetupPayload
+    "SVR", // AppServer
+    "DIS", // Discovery
+    "IM",  // InteractionModel
+    "TST", // Test
+    "OSS", // OperationalSessionSetup
+    "ATM", // Automation
+    "CSM", // CASESessionManager
+};
 
-#define ModuleNamesCount ((sizeof(ModuleNames) - 1) / chip::Logging::kMaxModuleNameLen)
-
-void GetModuleName(char (&buf)[chip::Logging::kMaxModuleNameLen + 1], uint8_t module)
+static char const * GetModuleName(LogModule module)
 {
-
-    const char * module_name = ModuleNames;
-    if (module < ModuleNamesCount)
-    {
-        module_name += module * chip::Logging::kMaxModuleNameLen;
-    }
-
-    memcpy(buf, module_name, chip::Logging::kMaxModuleNameLen);
-    buf[chip::Logging::kMaxModuleNameLen] = 0; // ensure null termination
+    return ModuleNames[(module < kLogModule_Max) ? module : kLogModule_NotSpecified];
 }
 
 } // namespace
@@ -164,7 +151,7 @@
  *                      correspond to the format specifiers in @a msg.
  *
  */
-DLL_EXPORT void Log(uint8_t module, uint8_t category, const char * msg, ...)
+void Log(uint8_t module, uint8_t category, const char * msg, ...)
 {
 
     va_list v;
@@ -173,7 +160,7 @@
     va_end(v);
 }
 
-DLL_EXPORT void LogByteSpan(uint8_t module, uint8_t category, const chip::ByteSpan & span)
+void LogByteSpan(uint8_t module, uint8_t category, const chip::ByteSpan & span)
 {
     // Maximum number of characters needed to print 8 byte buffer including formatting (0x)
     // 8 bytes * (2 nibbles per byte + 4 character for ", 0x") + null termination.
@@ -206,16 +193,8 @@
 
 void LogV(uint8_t module, uint8_t category, const char * msg, va_list args)
 {
-    if (!IsCategoryEnabled(category))
-    {
-        return;
-    }
-
-    char moduleName[chip::Logging::kMaxModuleNameLen + 1];
-    GetModuleName(moduleName, module);
-
+    const char * moduleName        = GetModuleName(static_cast<LogModule>(module));
     LogRedirectCallback_t redirect = sLogRedirectCallback.load();
-
     if (redirect != nullptr)
     {
         redirect(moduleName, category, msg, args);
@@ -228,41 +207,38 @@
 
 #if CHIP_LOG_FILTERING
 uint8_t gLogFilter = kLogCategory_Max;
-DLL_EXPORT bool IsCategoryEnabled(uint8_t category)
-{
-    return (category <= gLogFilter);
-}
 
-DLL_EXPORT uint8_t GetLogFilter()
+uint8_t GetLogFilter()
 {
     return gLogFilter;
 }
 
-DLL_EXPORT void SetLogFilter(uint8_t category)
+void SetLogFilter(uint8_t category)
 {
     gLogFilter = category;
 }
 
 #else  // CHIP_LOG_FILTERING
 
-DLL_EXPORT bool IsCategoryEnabled(uint8_t category)
-{
-    (void) category;
-    return true;
-}
-
-DLL_EXPORT uint8_t GetLogFilter()
+uint8_t GetLogFilter()
 {
     return kLogCategory_Max;
 }
 
-DLL_EXPORT void SetLogFilter(uint8_t category)
+void SetLogFilter(uint8_t category)
 {
-    (void) category;
+    IgnoreUnusedVariable(category);
 }
 #endif // CHIP_LOG_FILTERING
 
-#endif /* _CHIP_USE_LOGGING */
+#if CHIP_LOG_FILTERING
+bool IsCategoryEnabled(uint8_t category)
+{
+    return (category <= gLogFilter);
+}
+#endif // CHIP_LOG_FILTERING
+
+#endif // _CHIP_USE_LOGGING
 
 } // namespace Logging
 } // namespace chip
diff --git a/src/lib/support/logging/CHIPLogging.h b/src/lib/support/logging/CHIPLogging.h
index 9e6dc5c..28bdeb5 100644
--- a/src/lib/support/logging/CHIPLogging.h
+++ b/src/lib/support/logging/CHIPLogging.h
@@ -37,8 +37,7 @@
 
 #include <lib/core/CHIPConfig.h>
 
-#include <platform/logging/LogV.h>
-
+#include <lib/support/DLLUtil.h>
 #include <lib/support/EnforceFormat.h>
 #include <lib/support/logging/Constants.h>
 
@@ -46,6 +45,10 @@
 #include <stdarg.h>
 #include <stdint.h>
 
+#if CHIP_SYSTEM_CONFIG_PLATFORM_LOG && defined(CHIP_SYSTEM_CONFIG_PLATFORM_LOG_INCLUDE)
+#include CHIP_SYSTEM_CONFIG_PLATFORM_LOG_INCLUDE
+#endif
+
 #if CHIP_PW_TOKENIZER_LOGGING
 #include "pw_tokenizer/tokenize_to_global_handler_with_payload.h"
 #endif
@@ -68,7 +71,7 @@
  *        - #CHIP_ERROR_LOGGING
  *        - #CHIP_PROGRESS_LOGGING
  *        - #CHIP_DETAIL_LOGGING
- *         - #CHIP_AUTOMATION_LOGGING
+ *        - #CHIP_AUTOMATION_LOGGING
  *
  */
 
@@ -80,25 +83,13 @@
 
 namespace Logging {
 
+// Log redirection
 using LogRedirectCallback_t = void (*)(const char * module, uint8_t category, const char * msg, va_list args);
+DLL_EXPORT void SetLogRedirectCallback(LogRedirectCallback_t callback);
 
-void SetLogRedirectCallback(LogRedirectCallback_t callback);
-
-void LogV(uint8_t module, uint8_t category, const char * msg, va_list args) ENFORCE_FORMAT(3, 0);
-void Log(uint8_t module, uint8_t category, const char * msg, ...) ENFORCE_FORMAT(3, 4);
-
-void LogByteSpan(uint8_t module, uint8_t category, const ByteSpan & span);
-
-uint8_t GetLogFilter();
-void SetLogFilter(uint8_t category);
-
-#ifndef CHIP_ERROR_LOGGING
-#define CHIP_ERROR_LOGGING 1
-#endif
-
-#ifndef CHIP_LOG_FILTERING
-#define CHIP_LOG_FILTERING 1
-#endif
+// Log filtering (no-op unless CHIP_LOG_FILTERING is enabled)
+DLL_EXPORT uint8_t GetLogFilter();
+DLL_EXPORT void SetLogFilter(uint8_t category);
 
 #if CHIP_ERROR_LOGGING
 /**
@@ -109,23 +100,10 @@
  *   category.
  *
  */
-#ifndef ChipLogError
-#if CHIP_PW_TOKENIZER_LOGGING
-#define ChipLogError(MOD, MSG, ...)                                                                                                \
-    PW_TOKENIZE_TO_GLOBAL_HANDLER_WITH_PAYLOAD(                                                                                    \
-        (pw_tokenizer_Payload)((chip::Logging::kLogCategory_Error << 8) | chip::Logging::kLogModule_##MOD), MSG, __VA_ARGS__)
-#else
-#define ChipLogError(MOD, MSG, ...)                                                                                                \
-    chip::Logging::Log(chip::Logging::kLogModule_##MOD, chip::Logging::kLogCategory_Error, MSG, ##__VA_ARGS__)
-#endif
-#endif
-#else
+#define ChipLogError(MOD, MSG, ...) ChipInternalLog(MOD, Error, MSG, ##__VA_ARGS__)
+#else // CHIP_ERROR_LOGGING
 #define ChipLogError(MOD, MSG, ...) ((void) 0)
-#endif
-
-#ifndef CHIP_PROGRESS_LOGGING
-#define CHIP_PROGRESS_LOGGING 1
-#endif
+#endif // CHIP_ERROR_LOGGING
 
 #if CHIP_PROGRESS_LOGGING
 /**
@@ -136,23 +114,10 @@
  *   category.
  *
  */
-#ifndef ChipLogProgress
-#if CHIP_PW_TOKENIZER_LOGGING
-#define ChipLogProgress(MOD, MSG, ...)                                                                                             \
-    PW_TOKENIZE_TO_GLOBAL_HANDLER_WITH_PAYLOAD(                                                                                    \
-        (pw_tokenizer_Payload)((chip::Logging::kLogCategory_Progress << 8) | chip::Logging::kLogModule_##MOD), MSG, __VA_ARGS__)
-#else
-#define ChipLogProgress(MOD, MSG, ...)                                                                                             \
-    chip::Logging::Log(chip::Logging::kLogModule_##MOD, chip::Logging::kLogCategory_Progress, MSG, ##__VA_ARGS__)
-#endif
-#endif
-#else
+#define ChipLogProgress(MOD, MSG, ...) ChipInternalLog(MOD, Progress, MSG, ##__VA_ARGS__)
+#else // CHIP_PROGRESS_LOGGING
 #define ChipLogProgress(MOD, MSG, ...) ((void) 0)
-#endif
-
-#ifndef CHIP_DETAIL_LOGGING
-#define CHIP_DETAIL_LOGGING 1
-#endif
+#endif // CHIP_PROGRESS_LOGGING
 
 #if CHIP_DETAIL_LOGGING
 /**
@@ -163,32 +128,20 @@
  *   category.
  *
  */
-#ifndef ChipLogDetail
-#if CHIP_PW_TOKENIZER_LOGGING
-#define ChipLogDetail(MOD, MSG, ...)                                                                                               \
-    PW_TOKENIZE_TO_GLOBAL_HANDLER_WITH_PAYLOAD(                                                                                    \
-        (pw_tokenizer_Payload)((chip::Logging::kLogCategory_Detail << 8) | chip::Logging::kLogModule_##MOD), MSG, __VA_ARGS__)
-#else
-#define ChipLogDetail(MOD, MSG, ...)                                                                                               \
-    chip::Logging::Log(chip::Logging::kLogModule_##MOD, chip::Logging::kLogCategory_Detail, MSG, ##__VA_ARGS__)
-#endif
-#endif
-#else
+#define ChipLogDetail(MOD, MSG, ...) ChipInternalLog(MOD, Detail, MSG, ##__VA_ARGS__)
+
+/**
+ * @def ChipLogByteSpan(MOD, DATA)
+ *
+ * @brief
+ *   Log a byte span for the specified module in the 'Detail' category.
+ *
+ */
+#define ChipLogByteSpan(MOD, DATA) ChipInternalLogByteSpan(MOD, Detail, DATA)
+#else // CHP_DETAIL_LOGGING
 #define ChipLogDetail(MOD, MSG, ...) ((void) 0)
-#endif
-
-#if CHIP_DETAIL_LOGGING
-#ifndef ChipLogByteSpan
-#define ChipLogByteSpan(MOD, DATA)                                                                                                 \
-    chip::Logging::LogByteSpan(chip::Logging::kLogModule_##MOD, chip::Logging::kLogCategory_Detail, DATA)
-#endif
-#else
 #define ChipLogByteSpan(MOD, DATA) ((void) 0)
-#endif
-
-#ifndef CHIP_AUTOMATION_LOGGING
-#define CHIP_AUTOMATION_LOGGING 1
-#endif
+#endif // CHIP_DETAIL_LOGGING
 
 #if CHIP_AUTOMATION_LOGGING
 /**
@@ -199,51 +152,10 @@
  *   category.
  *
  */
-#ifndef ChipLogAutomation
-#if CHIP_PW_TOKENIZER_LOGGING
-#define ChipLogAutomation(MSG, ...)                                                                                                \
-    PW_TOKENIZE_TO_GLOBAL_HANDLER_WITH_PAYLOAD(                                                                                    \
-        (pw_tokenizer_Payload)((chip::Logging::kLogModule_Automation << 8) | chip::Logging::kLogModule_Automation), MSG,           \
-        __VA_ARGS__)
-#else
-#define ChipLogAutomation(MSG, ...)                                                                                                \
-    chip::Logging::Log(chip::Logging::kLogModule_Automation, chip::Logging::kLogCategory_Automation, MSG, ##__VA_ARGS__)
-#endif
-#endif
-#else
+#define ChipLogAutomation(MSG, ...) ChipInternalLog(Automation, Automation, MSG, ##__VA_ARGS__)
+#else // CHIP_AUTOMATION_LOGGING
 #define ChipLogAutomation(MOD, MSG, ...) ((void) 0)
-#endif
-
-#if CHIP_ERROR_LOGGING || CHIP_PROGRESS_LOGGING || CHIP_DETAIL_LOGGING || CHIP_AUTOMATION_LOGGING
-#define _CHIP_USE_LOGGING 1
-#else
-#define _CHIP_USE_LOGGING 0
-#endif /* CHIP_ERROR_LOGGING || CHIP_PROGRESS_LOGGING || CHIP_DETAIL_LOGGING || CHIP_AUTOMATION_LOGGING */
-
-#if _CHIP_USE_LOGGING
-
-/**
- * CHIP logging length constants
- */
-static constexpr uint16_t kMaxModuleNameLen  = 3;
-static constexpr uint16_t kMaxPrefixLen      = 3;
-static constexpr uint16_t kMaxSeparatorLen   = 2;
-static constexpr uint16_t kMaxTrailerLen     = 2;
-static constexpr uint16_t kMaxMessagePadding = (chip::Logging::kMaxPrefixLen + chip::Logging::kMaxModuleNameLen +
-                                                chip::Logging::kMaxSeparatorLen + chip::Logging::kMaxTrailerLen);
-
-void GetMessageWithPrefix(char * buf, uint8_t bufSize, uint8_t module, const char * msg);
-
-#else
-
-static inline void GetMessageWithPrefix(char * buf, uint8_t bufSize, uint8_t module, const char * msg)
-{
-    return;
-}
-
-#endif // _CHIP_USE_LOGGING
-
-bool IsCategoryEnabled(uint8_t category);
+#endif // CHIP_AUTOMATION_LOGGING
 
 /**
  *  @def ChipLogIfFalse(aCondition)
@@ -411,5 +323,79 @@
 #define ChipLogFormatScopedNodeId "<" ChipLogFormatX64 ", %d>"
 #define ChipLogValueScopedNodeId(id) ChipLogValueX64((id).GetNodeId()), (id).GetFabricIndex()
 
+/**
+ * CHIP Logging Implementation internals.
+ */
+
+#if CHIP_ERROR_LOGGING || CHIP_PROGRESS_LOGGING || CHIP_DETAIL_LOGGING || CHIP_AUTOMATION_LOGGING
+#define _CHIP_USE_LOGGING 1
+#else
+#define _CHIP_USE_LOGGING 0
+#endif // CHIP_ERROR_LOGGING || CHIP_PROGRESS_LOGGING || CHIP_DETAIL_LOGGING || CHIP_AUTOMATION_LOGGING
+
+#if _CHIP_USE_LOGGING
+
+static constexpr uint16_t kMaxModuleNameLen = 3;
+
+#if CHIP_LOG_FILTERING
+DLL_LOCAL bool IsCategoryEnabled(uint8_t category);
+#else  // CHIP_LOG_FILTERING
+DLL_LOCAL inline bool IsCategoryEnabled(uint8_t category)
+{
+    return true;
+}
+#endif // CHIP_LOG_FILTERING
+
+DLL_LOCAL void Log(uint8_t module, uint8_t category, const char * msg, ...) ENFORCE_FORMAT(3, 4);
+DLL_LOCAL void LogByteSpan(uint8_t module, uint8_t category, const ByteSpan & span);
+DLL_LOCAL void LogV(uint8_t module, uint8_t category, const char * msg, va_list args) ENFORCE_FORMAT(3, 0);
+
+#if CHIP_SYSTEM_CONFIG_PLATFORM_LOG
+#ifndef ChipPlatformLog
+#error "CHIP_SYSTEM_CONFIG_PLATFORM_LOG is enabled but ChipPlatformLog() is not defined"
+#endif
+#ifndef ChipPlatformLogByteSpan
+#error "CHIP_SYSTEM_CONFIG_PLATFORM_LOG is enabled but ChipPlatformLogByteSpan() is not defined"
+#endif
+#define ChipInternalLog(...) ChipPlatformLog(__VA_ARGS__)
+#define ChipInternalLogByteSpan(...) ChipPlatformLogByteSpan(__VA_ARGS__)
+#else // CHIP_SYSTEM_CONFIG_PLATFORM_LOG
+#define ChipInternalLog(MOD, CAT, MSG, ...) ChipInternalLogImpl(MOD, CAT, MSG, ##__VA_ARGS__)
+#define ChipInternalLogByteSpan(MOD, CAT, DATA) ChipInternalLogByteSpanImpl(MOD, CAT, DATA)
+#endif // CHIP_SYSTEM_CONFIG_PLATFORM_LOG
+
+#if CHIP_PW_TOKENIZER_LOGGING
+#define ChipInternalLogImpl(MOD, CAT, MSG, ...)                                                                                    \
+    do                                                                                                                             \
+    {                                                                                                                              \
+        if (chip::Logging::IsCategoryEnabled(chip::Logging::kLogCategory_##CAT))                                                   \
+        {                                                                                                                          \
+            PW_TOKENIZE_TO_GLOBAL_HANDLER_WITH_PAYLOAD(                                                                            \
+                (pw_tokenizer_Payload)((chip::Logging::kLogCategory_##CAT << 8) | chip::Logging::kLogModule_##MOD), MSG,           \
+                __VA_ARGS__);                                                                                                      \
+        }                                                                                                                          \
+    } while (0)
+#else // CHIP_PW_TOKENIZER_LOGGING
+#define ChipInternalLogImpl(MOD, CAT, MSG, ...)                                                                                    \
+    do                                                                                                                             \
+    {                                                                                                                              \
+        if (chip::Logging::IsCategoryEnabled(chip::Logging::kLogCategory_##CAT))                                                   \
+        {                                                                                                                          \
+            chip::Logging::Log(chip::Logging::kLogModule_##MOD, chip::Logging::kLogCategory_##CAT, MSG, ##__VA_ARGS__);            \
+        }                                                                                                                          \
+    } while (0)
+#endif // CHIP_PW_TOKENIZER_LOGGING
+
+#define ChipInternalLogByteSpanImpl(MOD, CAT, DATA)                                                                                \
+    do                                                                                                                             \
+    {                                                                                                                              \
+        if (chip::Logging::IsCategoryEnabled(chip::Logging::kLogCategory_##CAT))                                                   \
+        {                                                                                                                          \
+            chip::Logging::LogByteSpan(chip::Logging::kLogModule_##MOD, chip::Logging::kLogCategory_##CAT, DATA);                  \
+        }                                                                                                                          \
+    } while (0)
+
+#endif // _CHIP_USE_LOGGING
+
 } // namespace Logging
 } // namespace chip
diff --git a/src/platform/Darwin/BUILD.gn b/src/platform/Darwin/BUILD.gn
index 5544ce4..1a23fc1 100644
--- a/src/platform/Darwin/BUILD.gn
+++ b/src/platform/Darwin/BUILD.gn
@@ -13,6 +13,7 @@
 # limitations under the License.
 
 import("//build_overrides/chip.gni")
+import("//build_overrides/nlassert.gni")
 
 import("${chip_root}/src/platform/device.gni")
 
@@ -60,7 +61,7 @@
     "DnssdImpl.cpp",
     "DnssdImpl.h",
     "InetPlatformConfig.h",
-    "Logging.cpp",
+    "LoggingImpl.cpp",
     "MdnsError.cpp",
     "MdnsError.h",
     "NetworkCommissioningDriver.h",
@@ -91,6 +92,7 @@
   }
 
   deps = [
+    ":logging",
     "${chip_root}/src/lib/dnssd:platform_header",
     "${chip_root}/src/setup_payload",
   ]
@@ -123,3 +125,21 @@
     ]
   }
 }
+
+static_library("logging") {
+  sources = [
+    "Logging.h",
+    "Logging.mm",
+  ]
+
+  deps = [
+    "${chip_root}/src/lib/core:chip_config_header",  # for lib/support/Span.h
+    "${chip_root}/src/lib/support:attributes",
+    "${chip_root}/src/lib/support:logging_constants",
+    "${nlassert_root}:nlassert",  # for lib/support/Span.h
+  ]
+
+  configs += [ "${chip_root}/src:includes" ]
+  cflags = [ "-fobjc-arc" ]
+  frameworks = [ "Foundation.framework" ]
+}
diff --git a/src/platform/Darwin/Logging.cpp b/src/platform/Darwin/Logging.cpp
deleted file mode 100644
index 5124ed4..0000000
--- a/src/platform/Darwin/Logging.cpp
+++ /dev/null
@@ -1,78 +0,0 @@
-/* See Project chip LICENSE file for licensing information. */
-
-#include <lib/support/EnforceFormat.h>
-#include <lib/support/logging/Constants.h>
-#include <platform/logging/LogV.h>
-
-#include <lib/core/CHIPConfig.h>
-
-#include <os/log.h>
-
-#include <inttypes.h>
-#include <pthread.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/time.h>
-
-namespace chip {
-namespace Logging {
-namespace Platform {
-
-void ENFORCE_FORMAT(3, 0) LogV(const char * module, uint8_t category, const char * msg, va_list v)
-{
-    timeval time;
-    gettimeofday(&time, nullptr);
-    long ms = (time.tv_sec * 1000) + (time.tv_usec / 1000);
-
-    uint64_t ktid;
-    pthread_threadid_np(nullptr, &ktid);
-
-    char formattedMsg[CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE];
-    int32_t prefixLen   = snprintf(formattedMsg, sizeof(formattedMsg), "[%ld] [%lld:%lld] CHIP: [%s] ", ms, (long long) getpid(),
-                                 (long long) ktid, module);
-    static os_log_t log = os_log_create("com.csa.matter", "all");
-    if (prefixLen < 0)
-    {
-        // This should not happen
-        return;
-    }
-
-    if (static_cast<size_t>(prefixLen) >= sizeof(formattedMsg))
-    {
-        prefixLen = sizeof(formattedMsg) - 1;
-    }
-
-    vsnprintf(formattedMsg + prefixLen, sizeof(formattedMsg) - static_cast<size_t>(prefixLen), msg, v);
-
-    switch (category)
-    {
-    case kLogCategory_Error:
-        os_log_with_type(log, OS_LOG_TYPE_ERROR, "🔴 %{public}s", formattedMsg);
-#if TARGET_OS_MAC && TARGET_OS_IPHONE == 0
-        fprintf(stdout, "\033[1;31m");
-#endif
-        break;
-
-    case kLogCategory_Progress:
-        os_log_with_type(log, OS_LOG_TYPE_DEFAULT, "🔵 %{public}s", formattedMsg);
-#if TARGET_OS_MAC && TARGET_OS_IPHONE == 0
-        fprintf(stdout, "\033[0;32m");
-#endif
-        break;
-
-    case kLogCategory_Detail:
-        os_log_with_type(log, OS_LOG_TYPE_DEFAULT, "🟢 %{public}s", formattedMsg);
-#if TARGET_OS_MAC && TARGET_OS_IPHONE == 0
-        fprintf(stdout, "\033[0;34m");
-#endif
-        break;
-    }
-#if TARGET_OS_MAC && TARGET_OS_IPHONE == 0
-    fprintf(stdout, "%s\033[0m\n", formattedMsg);
-#endif
-}
-
-} // namespace Platform
-} // namespace Logging
-} // namespace chip
diff --git a/src/platform/Darwin/Logging.h b/src/platform/Darwin/Logging.h
new file mode 100644
index 0000000..7fcb82a
--- /dev/null
+++ b/src/platform/Darwin/Logging.h
@@ -0,0 +1,85 @@
+/*
+ *
+ *    Copyright (c) 2021 Project CHIP Authors
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#pragma once
+
+#include <lib/support/DLLUtil.h>
+#include <lib/support/logging/Constants.h>
+
+#include <os/log.h>
+
+#ifdef __OBJC__
+@class NSString;
+#endif // __OBJC__
+
+#define ChipPlatformLog(MOD, CAT, MSG, ...)                                                                                        \
+    do                                                                                                                             \
+    {                                                                                                                              \
+        ChipPlatformValidateLogFormat(MSG, ##__VA_ARGS__); /* validate once and ignore warnings from os_log() / Log() */           \
+        _Pragma("clang diagnostic push");                                                                                          \
+        _Pragma("clang diagnostic ignored \"-Wformat\"");                                                                          \
+        os_log_with_type(chip::Logging::Platform::LoggerForModule(chip::Logging::kLogModule_##MOD, #MOD),                          \
+                         static_cast<os_log_type_t>(chip::Logging::Platform::kOSLogCategory_##CAT), MSG, ##__VA_ARGS__);           \
+        ChipInternalLogImpl(MOD, CAT, MSG, ##__VA_ARGS__);                                                                         \
+        _Pragma("clang diagnostic pop");                                                                                           \
+    } while (0)
+
+#define ChipPlatformLogByteSpan(MOD, CAT, DATA)                                                                                    \
+    do                                                                                                                             \
+    {                                                                                                                              \
+        chip::Logging::Platform::LogByteSpan(chip::Logging::kLogModule_##MOD, #MOD,                                                \
+                                             static_cast<os_log_type_t>(chip::Logging::Platform::kOSLogCategory_##CAT), DATA);     \
+        ChipInternalLogByteSpanImpl(MOD, CAT, DATA);                                                                               \
+    } while (0)
+
+namespace chip {
+
+// Avoid includes cycle: Span.h indirectly includes CHIPLogging.h
+template <class T>
+class Span;
+using ByteSpan = Span<const uint8_t>;
+
+namespace Logging {
+namespace Platform {
+
+// Names align with chip::Logging::LogCategory
+enum OSLogCategory
+{
+    kOSLogCategory_Error      = OS_LOG_TYPE_ERROR,
+    kOSLogCategory_Progress   = OS_LOG_TYPE_DEFAULT,
+    kOSLogCategory_Detail     = OS_LOG_TYPE_INFO,
+    kOSLogCategory_Automation = OS_LOG_TYPE_DEFAULT,
+};
+
+DLL_LOCAL os_log_t LoggerForModule(chip::Logging::LogModule moduleId, char const * moduleName);
+DLL_LOCAL void LogByteSpan(chip::Logging::LogModule moduleId, char const * moduleName, os_log_type_t type,
+                           const chip::ByteSpan & span);
+
+// Helper constructs for compile-time validation of format strings for C++ / ObjC++ contexts.
+// Note that ObjC++ contexts are restricted to NSString style specifiers. Supporting os_log()
+// specifiers would require these to be emulated or stripped when log redirection is used.
+#ifdef __OBJC__
+DLL_LOCAL bool ValidateLogFormat(NSString * format, ...) __attribute__((format(__NSString__, 1, 0))); // not implemented
+#define ChipPlatformValidateLogFormat(F, ...) ((void) sizeof(chip::Logging::Platform::ValidateLogFormat(@F, ##__VA_ARGS__)))
+#else // __OBJC__
+DLL_LOCAL bool ValidateLogFormat(char const * format, ...) __attribute__((format(printf, 1, 0))); // not implemented
+#define ChipPlatformValidateLogFormat(F, ...) ((void) sizeof(chip::Logging::Platform::ValidateLogFormat(F, ##__VA_ARGS__)))
+#endif // __OBJC__
+
+} // namespace Platform
+} // namespace Logging
+} // namespace chip
diff --git a/src/platform/Darwin/Logging.mm b/src/platform/Darwin/Logging.mm
new file mode 100644
index 0000000..5bb7515
--- /dev/null
+++ b/src/platform/Darwin/Logging.mm
@@ -0,0 +1,68 @@
+/*
+ *
+ *    Copyright (c) 2021 Project CHIP Authors
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#if !__has_feature(objc_arc)
+#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
+#endif
+
+#include "Logging.h"
+
+#include <lib/support/Span.h>
+
+#import <Foundation/Foundation.h>
+#import <dispatch/dispatch.h>
+
+namespace chip {
+namespace Logging {
+    namespace Platform {
+
+        os_log_t LoggerForModule(chip::Logging::LogModule moduleID, char const * moduleName)
+        {
+            if (moduleID <= kLogModule_NotSpecified || kLogModule_Max <= moduleID) {
+                moduleID = kLogModule_NotSpecified;
+                moduleName = "Default";
+            }
+
+            static struct {
+                dispatch_once_t onceToken;
+                os_log_t logger;
+            } cache[kLogModule_Max];
+            auto & entry = cache[moduleID];
+            dispatch_once(&entry.onceToken, ^{
+                entry.logger = os_log_create("com.csa.matter", moduleName);
+            });
+            return entry.logger;
+        }
+
+        void LogByteSpan(
+            chip::Logging::LogModule moduleId, char const * moduleName, os_log_type_t type, const chip::ByteSpan & span)
+        {
+            os_log_t logger = LoggerForModule(moduleId, moduleName);
+            if (os_log_type_enabled(logger, type)) {
+                auto size = span.size();
+                auto data = span.data();
+                NSMutableString * string = [[NSMutableString alloc] initWithCapacity:(size * 6)]; // 6 characters per byte
+                for (size_t i = 0; i < size; i++) {
+                    [string appendFormat:((i % 8 != 7) ? @"0x%02x, " : @"0x%02x,\n"), data[i]];
+                }
+                os_log_with_type(logger, type, "%@", string);
+            }
+        }
+
+    } // namespace Platform
+} // namespace Logging
+} // namespace chip
diff --git a/src/platform/Darwin/LoggingImpl.cpp b/src/platform/Darwin/LoggingImpl.cpp
new file mode 100644
index 0000000..2d6c1b3
--- /dev/null
+++ b/src/platform/Darwin/LoggingImpl.cpp
@@ -0,0 +1,34 @@
+/*
+ *
+ *    Copyright (c) 2021 Project CHIP Authors
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#include <platform/logging/LogV.h>
+
+namespace chip {
+namespace Logging {
+namespace Platform {
+
+void LogV(const char * module, uint8_t category, const char * msg, va_list v)
+{
+    // ChipPlatformLog expands to an os_log call directly (see Logging.h), so
+    // we don't need to do anything further here. However his function and the
+    // call to it still exist because of scenarios where a different logging
+    // backend (usually stdio) is swapped in at link time, e.g. for unit tests.
+}
+
+} // namespace Platform
+} // namespace Logging
+} // namespace chip
diff --git a/src/platform/Darwin/SystemPlatformConfig.h b/src/platform/Darwin/SystemPlatformConfig.h
index 48613ba..19df500 100644
--- a/src/platform/Darwin/SystemPlatformConfig.h
+++ b/src/platform/Darwin/SystemPlatformConfig.h
@@ -40,5 +40,7 @@
 #define CHIP_SYSTEM_CONFIG_PLATFORM_PROVIDES_TIME 1
 #define CHIP_SYSTEM_CONFIG_USE_POSIX_TIME_FUNCTS 1
 #define CHIP_SYSTEM_CONFIG_POOL_USE_HEAP 1
+#define CHIP_SYSTEM_CONFIG_PLATFORM_LOG 1
+#define CHIP_SYSTEM_CONFIG_PLATFORM_LOG_INCLUDE <platform/Darwin/Logging.h>
 
 // ========== Platform-specific Configuration Overrides =========
diff --git a/src/platform/Linux/PlatformManagerImpl.cpp b/src/platform/Linux/PlatformManagerImpl.cpp
index e29f04b..ff753e4 100644
--- a/src/platform/Linux/PlatformManagerImpl.cpp
+++ b/src/platform/Linux/PlatformManagerImpl.cpp
@@ -285,8 +285,8 @@
 {
 
     GMainContext * context = g_main_loop_get_context(mGLibMainLoop);
-    VerifyOrReturnError(context != nullptr,
-                        (ChipLogDetail(DeviceLayer, "Failed to get GLib main loop context"), CHIP_ERROR_INTERNAL));
+    VerifyOrReturnError(context != nullptr, CHIP_ERROR_INTERNAL,
+                        ChipLogDetail(DeviceLayer, "Failed to get GLib main loop context"));
 
     // If we've been called from the GLib main loop thread itself, there is no reason to wait
     // for the callback, as it will be executed immediately by the g_main_context_invoke() call
diff --git a/src/platform/Linux/bluez/Helper.cpp b/src/platform/Linux/bluez/Helper.cpp
index b00ca75..ff0c73d 100644
--- a/src/platform/Linux/bluez/Helper.cpp
+++ b/src/platform/Linux/bluez/Helper.cpp
@@ -1438,7 +1438,7 @@
 
 CHIP_ERROR SendBluezIndication(BLE_CONNECTION_OBJECT apConn, chip::System::PacketBufferHandle apBuf)
 {
-    VerifyOrReturnError(!apBuf.IsNull(), (ChipLogError(DeviceLayer, "apBuf is NULL in %s", __func__), CHIP_ERROR_INVALID_ARGUMENT));
+    VerifyOrReturnError(!apBuf.IsNull(), CHIP_ERROR_INVALID_ARGUMENT, ChipLogError(DeviceLayer, "apBuf is NULL in %s", __func__));
     return PlatformMgrImpl().ScheduleOnGLibMainLoopThread(BluezC2Indicate, MakeConnectionDataBundle(apConn, apBuf));
 }
 
@@ -1476,33 +1476,32 @@
 CHIP_ERROR StartBluezAdv(BluezEndpoint * apEndpoint)
 {
     CHIP_ERROR err = PlatformMgrImpl().ScheduleOnGLibMainLoopThread(BluezAdvStart, apEndpoint);
-    VerifyOrReturnError(err == CHIP_NO_ERROR,
-                        (ChipLogError(Ble, "Failed to schedule BluezAdvStart() on CHIPoBluez thread"), CHIP_ERROR_INCORRECT_STATE));
+    VerifyOrReturnError(err == CHIP_NO_ERROR, CHIP_ERROR_INCORRECT_STATE,
+                        ChipLogError(Ble, "Failed to schedule BluezAdvStart() on CHIPoBluez thread"));
     return err;
 }
 
 CHIP_ERROR StopBluezAdv(BluezEndpoint * apEndpoint)
 {
     CHIP_ERROR err = PlatformMgrImpl().ScheduleOnGLibMainLoopThread(BluezAdvStop, apEndpoint);
-    VerifyOrReturnError(err == CHIP_NO_ERROR,
-                        (ChipLogError(Ble, "Failed to schedule BluezAdvStop() on CHIPoBluez thread"), CHIP_ERROR_INCORRECT_STATE));
+    VerifyOrReturnError(err == CHIP_NO_ERROR, CHIP_ERROR_INCORRECT_STATE,
+                        ChipLogError(Ble, "Failed to schedule BluezAdvStop() on CHIPoBluez thread"));
     return err;
 }
 
 CHIP_ERROR BluezAdvertisementSetup(BluezEndpoint * apEndpoint)
 {
     CHIP_ERROR err = PlatformMgrImpl().ScheduleOnGLibMainLoopThread(BluezAdvSetup, apEndpoint);
-    VerifyOrReturnError(err == CHIP_NO_ERROR,
-                        (ChipLogError(Ble, "Failed to schedule BluezAdvSetup() on CHIPoBluez thread"), CHIP_ERROR_INCORRECT_STATE));
+    VerifyOrReturnError(err == CHIP_NO_ERROR, CHIP_ERROR_INCORRECT_STATE,
+                        ChipLogError(Ble, "Failed to schedule BluezAdvSetup() on CHIPoBluez thread"));
     return err;
 }
 
 CHIP_ERROR BluezGattsAppRegister(BluezEndpoint * apEndpoint)
 {
     CHIP_ERROR err = PlatformMgrImpl().ScheduleOnGLibMainLoopThread(BluezPeripheralRegisterApp, apEndpoint);
-    VerifyOrReturnError(
-        err == CHIP_NO_ERROR,
-        (ChipLogError(Ble, "Failed to schedule BluezPeripheralRegisterApp() on CHIPoBluez thread"), CHIP_ERROR_INCORRECT_STATE));
+    VerifyOrReturnError(err == CHIP_NO_ERROR, CHIP_ERROR_INCORRECT_STATE,
+                        ChipLogError(Ble, "Failed to schedule BluezPeripheralRegisterApp() on CHIPoBluez thread"));
     return err;
 }
 
@@ -1631,7 +1630,7 @@
 
 CHIP_ERROR BluezSendWriteRequest(BLE_CONNECTION_OBJECT apConn, chip::System::PacketBufferHandle apBuf)
 {
-    VerifyOrReturnError(!apBuf.IsNull(), (ChipLogError(DeviceLayer, "apBuf is NULL in %s", __func__), CHIP_ERROR_INVALID_ARGUMENT));
+    VerifyOrReturnError(!apBuf.IsNull(), CHIP_ERROR_INVALID_ARGUMENT, ChipLogError(DeviceLayer, "apBuf is NULL in %s", __func__));
     return PlatformMgrImpl().ScheduleOnGLibMainLoopThread(SendWriteRequestImpl, MakeConnectionDataBundle(apConn, apBuf));
 }
 
diff --git a/src/platform/Tizen/DnssdImpl.cpp b/src/platform/Tizen/DnssdImpl.cpp
index e2ab151..2bd1ed2 100644
--- a/src/platform/Tizen/DnssdImpl.cpp
+++ b/src/platform/Tizen/DnssdImpl.cpp
@@ -120,8 +120,8 @@
     rCtx->mMainLoop = mainLoop;
 
     int ret = dnssd_register_local_service(rCtx->mServiceHandle, OnRegister, rCtx);
-    VerifyOrReturnError(ret == DNSSD_ERROR_NONE,
-                        (ChipLogError(DeviceLayer, "dnssd_register_local_service() failed. ret: %d", ret), false));
+    VerifyOrReturnValue(ret == DNSSD_ERROR_NONE, false,
+                        ChipLogError(DeviceLayer, "dnssd_register_local_service() failed. ret: %d", ret));
 
     rCtx->mIsRegistered = true;
     return true;
@@ -209,8 +209,8 @@
     VerifyOrExit(ret == DNSSD_ERROR_NONE, ChipLogError(DeviceLayer, "dnssd_service_get_interface() failed. ret: %d", ret));
 
     interfaceId = if_nametoindex(ifaceName);
-    VerifyOrExit(interfaceId > 0,
-                 (ChipLogError(DeviceLayer, "if_nametoindex() failed. errno: %d", errno), ret = DNSSD_ERROR_OPERATION_FAILED));
+    VerifyOrExit(interfaceId > 0, ChipLogError(DeviceLayer, "if_nametoindex() failed. errno: %d", errno);
+                 ret = DNSSD_ERROR_OPERATION_FAILED);
 
     if (state == DNSSD_SERVICE_STATE_AVAILABLE)
     {
@@ -253,8 +253,8 @@
     else
     {
         char iface[IF_NAMESIZE + 1] = "";
-        VerifyOrReturnError(if_indextoname(interfaceId, iface) != nullptr,
-                            (ChipLogError(DeviceLayer, "if_indextoname() failed. errno: %d", errno), false));
+        VerifyOrReturnValue(if_indextoname(interfaceId, iface) != nullptr, false,
+                            ChipLogError(DeviceLayer, "if_indextoname() failed. errno: %d", errno));
         ret = dnssd_browse_service(bCtx->mType, iface, &bCtx->mBrowserHandle, OnBrowse, bCtx);
     }
 
@@ -407,8 +407,7 @@
     rCtx->mMainLoop = mainLoop;
 
     int ret = dnssd_resolve_service(rCtx->mServiceHandle, OnResolve, rCtx);
-    VerifyOrReturnError(ret == DNSSD_ERROR_NONE,
-                        (ChipLogError(DeviceLayer, "dnssd_resolve_service() failed. ret: %d", ret), false));
+    VerifyOrReturnValue(ret == DNSSD_ERROR_NONE, false, ChipLogError(DeviceLayer, "dnssd_resolve_service() failed. ret: %d", ret));
 
     rCtx->mIsResolving = true;
     return true;
@@ -520,7 +519,7 @@
         std::lock_guard<std::mutex> lock(mMutex);
 
         auto iServiceCtx = std::find_if(mContexts.begin(), mContexts.end(), [fullType, service, interfaceId](const auto & ctx) {
-            VerifyOrReturnError(ctx->mContextType == ContextType::Register, false);
+            VerifyOrReturnValue(ctx->mContextType == ContextType::Register, false);
             auto * rCtx = static_cast<RegisterContext *>(ctx.get());
             return strcmp(rCtx->mName, service.mName) == 0 && strcmp(rCtx->mType, fullType.c_str()) == 0 &&
                 rCtx->mPort == service.mPort && rCtx->mInterfaceId == interfaceId;
@@ -552,25 +551,26 @@
     // Local service will be freed by the RegisterContext destructor
     int ret            = dnssd_create_local_service(fullType.c_str(), &serviceCtx->mServiceHandle);
     auto serviceHandle = serviceCtx->mServiceHandle;
-    VerifyOrExit(ret == DNSSD_ERROR_NONE,
-                 (ChipLogError(DeviceLayer, "dnssd_create_local_service() failed. ret: %d", ret), err = GetChipError(ret)));
+    VerifyOrExit(ret == DNSSD_ERROR_NONE, ChipLogError(DeviceLayer, "dnssd_create_local_service() failed. ret: %d", ret);
+                 err = GetChipError(ret));
 
     ret = dnssd_service_set_name(serviceHandle, service.mName);
-    VerifyOrExit(ret == DNSSD_ERROR_NONE,
-                 (ChipLogError(DeviceLayer, "dnssd_service_set_name() failed. ret: %d", ret), err = GetChipError(ret)));
+    VerifyOrExit(ret == DNSSD_ERROR_NONE, ChipLogError(DeviceLayer, "dnssd_service_set_name() failed. ret: %d", ret);
+                 err = GetChipError(ret));
 
     ret = dnssd_service_set_port(serviceHandle, service.mPort);
-    VerifyOrExit(ret == DNSSD_ERROR_NONE,
-                 (ChipLogError(DeviceLayer, "dnssd_service_set_port() failed. ret: %d", ret), err = GetChipError(ret)));
+    VerifyOrExit(ret == DNSSD_ERROR_NONE, ChipLogError(DeviceLayer, "dnssd_service_set_port() failed. ret: %d", ret);
+                 err = GetChipError(ret));
 
     if (interfaceId > 0)
     {
         char iface[IF_NAMESIZE + 1] = "";
         VerifyOrExit(if_indextoname(interfaceId, iface) != nullptr,
-                     (ChipLogError(DeviceLayer, "if_indextoname() failed. errno: %d", errno), err = CHIP_ERROR_INTERNAL));
+                     ChipLogError(DeviceLayer, "if_indextoname() failed. errno: %d", errno);
+                     err = CHIP_ERROR_INTERNAL);
         ret = dnssd_service_set_interface(serviceHandle, iface);
-        VerifyOrExit(ret == DNSSD_ERROR_NONE,
-                     (ChipLogError(DeviceLayer, "dnssd_service_set_interface() failed. ret: %d", ret), err = GetChipError(ret)));
+        VerifyOrExit(ret == DNSSD_ERROR_NONE, ChipLogError(DeviceLayer, "dnssd_service_set_interface() failed. ret: %d", ret);
+                     err = GetChipError(ret));
     }
 
     for (size_t i = 0; i < service.mTextEntrySize; ++i)
@@ -578,8 +578,8 @@
         TextEntry entry = service.mTextEntries[i];
         VerifyOrReturnError(chip::CanCastTo<unsigned short>(entry.mDataSize), CHIP_ERROR_INVALID_ARGUMENT);
         ret = dnssd_service_add_txt_record(serviceHandle, entry.mKey, static_cast<unsigned short>(entry.mDataSize), entry.mData);
-        VerifyOrExit(ret == DNSSD_ERROR_NONE,
-                     (ChipLogError(DeviceLayer, "dnssd_service_add_txt_record() failed. ret: %d", ret), err = GetChipError(ret)));
+        VerifyOrExit(ret == DNSSD_ERROR_NONE, ChipLogError(DeviceLayer, "dnssd_service_add_txt_record() failed. ret: %d", ret);
+                     err = GetChipError(ret));
     }
 
     ok = DeviceLayer::Internal::MainLoop::Instance().AsyncRequest(RegisterAsync, serviceCtx);
@@ -655,12 +655,13 @@
     {
         char iface[IF_NAMESIZE + 1] = "";
         VerifyOrExit(if_indextoname(interfaceId, iface) != nullptr,
-                     (ChipLogError(DeviceLayer, "if_indextoname() failed. errno: %d", errno), err = CHIP_ERROR_INTERNAL));
+                     ChipLogError(DeviceLayer, "if_indextoname() failed. errno: %d", errno);
+                     err = CHIP_ERROR_INTERNAL);
         ret = dnssd_create_remote_service(fullType.c_str(), browseResult.mName, iface, &resolveCtx->mServiceHandle);
     }
 
-    VerifyOrExit(ret == DNSSD_ERROR_NONE,
-                 (ChipLogError(DeviceLayer, "dnssd_create_remote_service() failed. ret: %d", ret), err = GetChipError(ret)));
+    VerifyOrExit(ret == DNSSD_ERROR_NONE, ChipLogError(DeviceLayer, "dnssd_create_remote_service() failed. ret: %d", ret);
+                 err = GetChipError(ret));
 
     ok = DeviceLayer::Internal::MainLoop::Instance().AsyncRequest(ResolveAsync, resolveCtx);
     VerifyOrExit(ok, err = CHIP_ERROR_INTERNAL);
diff --git a/src/platform/Tizen/ThreadStackManagerImpl.cpp b/src/platform/Tizen/ThreadStackManagerImpl.cpp
index c7cca44..75c2dec 100644
--- a/src/platform/Tizen/ThreadStackManagerImpl.cpp
+++ b/src/platform/Tizen/ThreadStackManagerImpl.cpp
@@ -444,9 +444,8 @@
     int threadErr;
 
     threadErr = thread_get_extended_address(mThreadInstance, &extAddr);
-    VerifyOrReturnError(
-        threadErr == THREAD_ERROR_NONE,
-        (ChipLogError(DeviceLayer, "thread_get_extended_address() failed. ret: %d", threadErr), CHIP_ERROR_INTERNAL));
+    VerifyOrReturnError(threadErr == THREAD_ERROR_NONE, CHIP_ERROR_INTERNAL,
+                        ChipLogError(DeviceLayer, "thread_get_extended_address() failed. ret: %d", threadErr));
 
     extAddr = htobe64(extAddr);
     memcpy(buf, &extAddr, sizeof(extAddr));
@@ -592,8 +591,8 @@
 
     /* Get external ip address */
     threadErr = thread_get_ipaddr(mThreadInstance, _ThreadIpAddressCb, THREAD_IPADDR_TYPE_MLEID, nullptr);
-    VerifyOrReturnError(threadErr == THREAD_ERROR_NONE,
-                        (ChipLogError(DeviceLayer, "thread_get_ipaddr() failed. ret: %d", threadErr), CHIP_ERROR_INTERNAL));
+    VerifyOrReturnError(threadErr == THREAD_ERROR_NONE, CHIP_ERROR_INTERNAL,
+                        ChipLogError(DeviceLayer, "thread_get_ipaddr() failed. ret: %d", threadErr));
 
     return CHIP_NO_ERROR;
 }
diff --git a/src/platform/logging/BUILD.gn b/src/platform/logging/BUILD.gn
index 038f942..4025283 100644
--- a/src/platform/logging/BUILD.gn
+++ b/src/platform/logging/BUILD.gn
@@ -16,7 +16,7 @@
     deps = [
       ":headers",
       "${chip_root}/src/lib/core:chip_config_header",
-      "${chip_root}/src/lib/support:enforce_format",
+      "${chip_root}/src/lib/support:attributes",
       "${chip_root}/src/lib/support:logging_constants",
       "${chip_root}/src/platform:platform_buildconfig",
     ]
@@ -25,14 +25,38 @@
   }
 }
 
+# We need to reference the output file of ":stdio" at build time,
+# but get_target_outputs() does not work for binary targets. As a
+# workaround, define a reasonable path and make the target use it.
+stdio_archive = "$root_out_dir/liblogging-stdio.a"
+
 static_library("stdio") {
   sources = [ "impl/stdio/Logging.cpp" ]
 
   deps = [
     ":headers",
     "${chip_root}/src/lib/core:chip_config_header",
-    "${chip_root}/src/lib/support:enforce_format",
+    "${chip_root}/src/lib/support:attributes",
     "${chip_root}/src/lib/support:logging_constants",
     "${chip_root}/src/platform:platform_buildconfig",
   ]
+
+  # Ensure we end up with the expected output file name
+  output_dir = get_path_info(stdio_archive, "dir")
+  output_name = get_path_info(stdio_archive, "name")
+  output_extension = get_path_info(stdio_archive, "extension")
+  output_prefix_override = true
+}
+
+# Depending on this target (via public_deps) pulls in the stdio
+# logger and ensures it takes precendce over the platform backend.
+group("force_stdio") {
+  deps = [ ":stdio" ]
+  public_configs = [ ":force_stdio_config" ]
+}
+
+config("force_stdio_config") {
+  # Ensure the linker sees the stdio implementation first. This
+  # works because ldflags come before inputs on the command line.
+  ldflags = [ rebase_path(stdio_archive, root_build_dir) ]
 }
diff --git a/src/system/SystemConfig.h b/src/system/SystemConfig.h
index 87171af..11ba2a0 100644
--- a/src/system/SystemConfig.h
+++ b/src/system/SystemConfig.h
@@ -175,18 +175,6 @@
 /* Configuration option variables defined below */
 
 /**
- *  @def CHIP_SYSTEM_CONFIG_NO_LOCKING
- *
- *  @brief
- *      Disable the use of locking within the system layer.
- *
- *      Unless you are simulating an LwIP-based system on a Unix-style host, this value should be left at its default.
- */
-#ifndef CHIP_SYSTEM_CONFIG_NO_LOCKING
-#define CHIP_SYSTEM_CONFIG_NO_LOCKING 0
-#endif /* CHIP_SYSTEM_CONFIG_NO_LOCKING */
-
-/**
  *  @def CHIP_SYSTEM_CONFIG_POSIX_LOCKING
  *
  *  @brief
@@ -506,6 +494,18 @@
 #endif /* CHIP_SYSTEM_CONFIG_HEADER_RESERVE_SIZE */
 
 /**
+ *  @def CHIP_SYSTEM_CONFIG_PLATFORM_LOG
+ *
+ *  @brief
+ *      Defines whether (1) or not (0) the system uses a platform-specific logging implementation.
+ *
+ *  See CHIPLogging.h for details.
+ */
+#ifndef CHIP_SYSTEM_CONFIG_PLATFORM_LOG
+#define CHIP_SYSTEM_CONFIG_PLATFORM_LOG 0
+#endif // CHIP_SYSTEM_CONFIG_PLATFORM_LOG
+
+/**
  *  @def CHIP_SYSTEM_CONFIG_PLATFORM_PROVIDES_TIME
  *
  *  @brief