diff --git a/.pubnub.yml b/.pubnub.yml index a327510cd6..72a596f204 100644 --- a/.pubnub.yml +++ b/.pubnub.yml @@ -1,9 +1,9 @@ name: kotlin -version: 10.5.8 +version: 10.6.0 schema: 1 scm: github.com/pubnub/kotlin files: - - build/libs/pubnub-kotlin-10.5.8-all.jar + - build/libs/pubnub-kotlin-10.6.0-all.jar sdks: - type: library @@ -23,8 +23,8 @@ sdks: - distribution-type: library distribution-repository: maven - package-name: pubnub-kotlin-10.5.8 - location: https://repo.maven.apache.org/maven2/com/pubnub/pubnub-kotlin/10.5.8/pubnub-kotlin-10.5.8.jar + package-name: pubnub-kotlin-10.6.0 + location: https://repo.maven.apache.org/maven2/com/pubnub/pubnub-kotlin/10.6.0/pubnub-kotlin-10.6.0.jar supported-platforms: supported-operating-systems: Android: @@ -121,6 +121,15 @@ sdks: license-url: https://www.apache.org/licenses/LICENSE-2.0.txt is-required: Required changelog: + - date: 2025-09-11 + version: v10.6.0 + changes: + - type: feature + text: "Added structured log statements throughout the system in transport layer, crypto module, serialization, API calls, etc." + - type: feature + text: "Added deprecation warning for logVerbosity and httpLoggingInterceptor config params. For logging configuration we advise using SLF4J implementation lib like logback or log4j2 and their config capabilities." + - type: feature + text: "Added new config property called customLoggers, which can bu used when customer needs can not be implemented using configuration options of SLF4J implementation libs like logback or log4j2." - date: 2025-08-06 version: v10.5.8 changes: diff --git a/CHANGELOG.md b/CHANGELOG.md index a282d48615..1556e0a38a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## v10.6.0 +September 11 2025 + +#### Added +- Added structured log statements throughout the system in transport layer, crypto module, serialization, API calls, etc. +- Added deprecation warning for logVerbosity and httpLoggingInterceptor config params. For logging configuration we advise using SLF4J implementation lib like logback or log4j2 and their config capabilities. +- Added new config property called customLoggers, which can bu used when customer needs can not be implemented using configuration options of SLF4J implementation libs like logback or log4j2. + ## v10.5.8 August 06 2025 diff --git a/README.md b/README.md index eb1108be8a..db825345c4 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ You will need the publish and subscribe keys to authenticate your app. Get your com.pubnub pubnub-kotlin - 10.5.8 + 10.6.0 ``` diff --git a/gradle.properties b/gradle.properties index 9b729069a8..86bedca76b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -18,7 +18,7 @@ RELEASE_SIGNING_ENABLED=true SONATYPE_HOST=DEFAULT SONATYPE_AUTOMATIC_RELEASE=false GROUP=com.pubnub -VERSION_NAME=10.5.8 +VERSION_NAME=10.6.0 POM_PACKAGING=jar POM_NAME=PubNub SDK diff --git a/pubnub-gson/pubnub-gson-api/src/main/java/com/pubnub/api/java/v2/PNConfiguration.kt b/pubnub-gson/pubnub-gson-api/src/main/java/com/pubnub/api/java/v2/PNConfiguration.kt index 7330321ce2..a499fc9180 100644 --- a/pubnub-gson/pubnub-gson-api/src/main/java/com/pubnub/api/java/v2/PNConfiguration.kt +++ b/pubnub-gson/pubnub-gson-api/src/main/java/com/pubnub/api/java/v2/PNConfiguration.kt @@ -4,6 +4,7 @@ import com.pubnub.api.UserId import com.pubnub.api.crypto.CryptoModule import com.pubnub.api.enums.PNHeartbeatNotificationOptions import com.pubnub.api.enums.PNLogVerbosity +import com.pubnub.api.logging.CustomLogger import com.pubnub.api.retry.RetryConfiguration import okhttp3.Authenticator import okhttp3.CertificatePinner @@ -91,6 +92,13 @@ interface PNConfiguration : com.pubnub.api.v2.PNConfiguration { /** * Set to [PNLogVerbosity.BODY] to enable logging of network traffic, otherwise se to [PNLogVerbosity.NONE]. */ + @Deprecated( + message = "LogVerbosity setting is deprecated and will be removed in future versions. " + + "For logging configuration:\n" + + "1. Use an SLF4J implementation (recommended)\n" + + "2. Or implement CustomLogger interface and set via customLoggers property", + level = DeprecationLevel.WARNING + ) val logVerbosity: PNLogVerbosity /** @@ -248,6 +256,10 @@ interface PNConfiguration : com.pubnub.api.v2.PNConfiguration { * * @see [HttpLoggingInterceptor] */ + @Deprecated( + message = "This setting is deprecated. Use customLoggers instead", + level = DeprecationLevel.WARNING + ) val httpLoggingInterceptor: HttpLoggingInterceptor? /** @@ -301,6 +313,12 @@ interface PNConfiguration : com.pubnub.api.v2.PNConfiguration { */ val managePresenceListManually: Boolean + /** + * Custom loggers list for creating additional logger instances. + * Use it if your slf4j implementation like logback, log4j2, etc. can't meet your specific logging requirements. + */ + val customLoggers: List? + override fun build(): PNConfiguration override fun setUserId(userId: UserId): Builder @@ -337,6 +355,13 @@ interface PNConfiguration : com.pubnub.api.v2.PNConfiguration { /** * Set to [PNLogVerbosity.BODY] to enable logging of network traffic, otherwise se to [PNLogVerbosity.NONE]. */ + @Deprecated( + message = "LogVerbosity setting is deprecated and will be removed in future versions. " + + "For logging configuration:\n" + + "1. Use an SLF4J implementation (recommended)\n" + + "2. Or implement CustomLogger interface and set via customLoggers property", + level = DeprecationLevel.WARNING + ) fun logVerbosity(logVerbosity: PNLogVerbosity): Builder /** @@ -479,6 +504,10 @@ interface PNConfiguration : com.pubnub.api.v2.PNConfiguration { * * @see [HttpLoggingInterceptor] */ + @Deprecated( + message = "This setting is deprecated. Use customLoggers instead", + level = DeprecationLevel.WARNING + ) fun httpLoggingInterceptor(httpLoggingInterceptor: HttpLoggingInterceptor?): Builder /** @@ -533,6 +562,12 @@ interface PNConfiguration : com.pubnub.api.v2.PNConfiguration { * @see PNConfigurationImpl.heartbeatInterval */ fun managePresenceListManually(managePresenceListManually: Boolean): Builder + + /** + * Custom loggers list for creating additional logger instances. + * Use it if your slf4j implementation like logback, log4j2, etc. can't meet your specific logging requirements. + */ + fun customLoggers(customLoggers: List?): Builder } } diff --git a/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/LoggingIntegrationTest.java b/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/LoggingIntegrationTest.java new file mode 100644 index 0000000000..e183f1ec6b --- /dev/null +++ b/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/LoggingIntegrationTest.java @@ -0,0 +1,105 @@ +package com.pubnub.api.integration; + +import com.pubnub.api.PubNubException; +import com.pubnub.api.UserId; +import com.pubnub.api.integration.util.BaseIntegrationTest; +import com.pubnub.api.integration.util.CustomLoggerTestImpl; +import com.pubnub.api.integration.util.ITTestConfig; +import com.pubnub.api.integration.util.RandomGenerator; +import com.pubnub.api.java.PubNub; +import com.pubnub.api.java.v2.PNConfiguration; +import com.pubnub.api.logging.LogMessageContent; +import com.pubnub.api.logging.LogMessageType; +import org.aeonbits.owner.ConfigFactory; +import org.junit.Test; + +import java.util.Collections; +import java.util.UUID; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class LoggingIntegrationTest extends BaseIntegrationTest { + final ITTestConfig itTestConfig = ConfigFactory.create(ITTestConfig.class, System.getenv()); + + @Test + public void testCanLogMessagesUsingCustomLogger() throws PubNubException, InterruptedException { + // Clear any previous messages + CustomLoggerTestImpl.clear(); + + String expectedUuid = UUID.randomUUID().toString(); + String expectedChannel = "test-channel-" + RandomGenerator.newValue(8); + + PNConfiguration.Builder configBuilder = PNConfiguration.builder( + new UserId(expectedUuid), + itTestConfig.subscribeKey() + ); + configBuilder.publishKey(itTestConfig.publishKey()); + configBuilder.customLoggers(Collections.singletonList(new CustomLoggerTestImpl())); + + PubNub pubNub = PubNub.create(configBuilder.build()); + + // Publish a message to generate logs + pubNub.publish() + .channel(expectedChannel) + .message(generatePayload()) + .customMessageType("myType") + .sync(); + + // Verify logging + assertFalse("Should have received string messages", CustomLoggerTestImpl.stringMessages.isEmpty()); + assertFalse("Should have received LogMessage objects", CustomLoggerTestImpl.logMessages.isEmpty()); + + // Verify content - string messages + assertTrue( + "Should have called publish on the expected channel", + CustomLoggerTestImpl.stringMessages.stream().anyMatch(msg -> + msg.contains("PublishEndpoint") && msg.contains(expectedChannel) + ) + ); + + assertTrue( + "Should have called publish on the expected channel", + CustomLoggerTestImpl.stringMessages.stream().anyMatch(msg -> + msg.contains("NetworkRequest") && msg.contains(expectedChannel) + ) + ); + + assertTrue( + "Should have called publish on the expected channel", + CustomLoggerTestImpl.stringMessages.stream().anyMatch(msg -> + msg.contains("NetworkResponse") && msg.contains(expectedChannel) + ) + ); + + // Verify content - LogMessage objects + assertTrue( + "Should have called publish on the expected channel", + CustomLoggerTestImpl.logMessages.stream().anyMatch(msg -> + msg.getType() == LogMessageType.OBJECT && + msg.getLocation().contains("PublishEndpoint") && + (msg.getMessage() instanceof LogMessageContent.Object) && + expectedChannel.equals(((LogMessageContent.Object) msg.getMessage()).getMessage().get("channel")) + ) + ); + + assertTrue( + "Should have called publish API. LogMessage type should be NETWORK_REQUEST", + CustomLoggerTestImpl.logMessages.stream().anyMatch(msg -> + msg.getType() == LogMessageType.NETWORK_REQUEST && + msg.getLocation().contains("publish") + ) + ); + + assertTrue( + "Should have called publish API. LogMessage type should be NETWORK_RESPONSE", + CustomLoggerTestImpl.logMessages.stream().anyMatch(msg -> + msg.getType() == LogMessageType.NETWORK_RESPONSE && + msg.getLocation().contains("publish") + ) + ); + + pubNub.destroy(); + } + +} diff --git a/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/MessageActionsTest.java b/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/MessageActionsTest.java index e5d4e94229..a46e215643 100644 --- a/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/MessageActionsTest.java +++ b/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/MessageActionsTest.java @@ -231,7 +231,7 @@ public void onMore(List actions) { @Override public void onDone() { - log.error(String.format("onDone %s", count.get())); + System.out.println(String.format("onDone %s", count.get())); success.set(count.get() == messageCount); } }); diff --git a/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/PNConfigurationIntegrationTests.java b/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/PNConfigurationIntegrationTests.java index 3aaad6687b..dd1135e9da 100644 --- a/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/PNConfigurationIntegrationTests.java +++ b/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/PNConfigurationIntegrationTests.java @@ -2,6 +2,7 @@ import com.pubnub.api.PubNubException; import com.pubnub.api.UserId; +import com.pubnub.api.integration.util.CustomLoggerTestImpl; import com.pubnub.api.integration.util.ITTestConfig; import com.pubnub.api.integration.util.Utils; import com.pubnub.api.java.PubNub; @@ -11,6 +12,8 @@ import org.junit.Assert; import org.junit.Test; +import java.util.Arrays; + public class PNConfigurationIntegrationTests { final ITTestConfig itTestConfig = ConfigFactory.create(ITTestConfig.class, System.getenv()); @@ -35,12 +38,14 @@ public void createConfigurationWithConfigurationActionBlock() throws PubNubExcep String expectedUuid = PubNub.generateUUID(); PNConfiguration.Builder configBuilder = PNConfiguration.builder(new UserId(expectedUuid), itTestConfig.subscribeKey()) - .publishKey(itTestConfig.publishKey()); + .publishKey(itTestConfig.publishKey()) + .customLoggers( Arrays.asList(new CustomLoggerTestImpl())); PubNub pubNub = PubNub.create(configBuilder.build()); Assert.assertEquals(expectedUuid, pubNub.getConfiguration().getUserId().getValue()); Assert.assertEquals(itTestConfig.subscribeKey(), pubNub.getConfiguration().getSubscribeKey()); Assert.assertEquals(itTestConfig.publishKey(), pubNub.getConfiguration().getPublishKey()); + Assert.assertTrue(pubNub.getConfiguration().getCustomLoggers().get(0) instanceof CustomLoggerTestImpl); } @Test diff --git a/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/objects/channel/ChannelMetadataIT.java b/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/objects/channel/ChannelMetadataIT.java index 16ff51e263..2276a30fc9 100644 --- a/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/objects/channel/ChannelMetadataIT.java +++ b/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/objects/channel/ChannelMetadataIT.java @@ -12,8 +12,6 @@ import org.jetbrains.annotations.NotNull; import org.junit.After; import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.HashMap; @@ -35,7 +33,6 @@ import static org.junit.Assert.assertNotNull; public class ChannelMetadataIT extends ObjectsApiBaseIT { - private static final Logger LOG = LoggerFactory.getLogger(ChannelMetadataIT.class); private static final int NUMBER_OF_RANDOM_TEST_NAMES = 10; private static final int FETCH_LIMIT = 3; @@ -272,7 +269,7 @@ public void cleanUp() { .channel(setChannelMetadataResult.getData().getId()) .sync(); } catch (Exception e) { - LOG.warn("Could not cleanup {}", setChannelMetadataResult, e); + System.out.printf("Could not cleanup {}", setChannelMetadataResult); } }); } diff --git a/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/objects/members/ChannelMembersIT.java b/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/objects/members/ChannelMembersIT.java index 677d602f48..e4450a44ae 100644 --- a/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/objects/members/ChannelMembersIT.java +++ b/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/objects/members/ChannelMembersIT.java @@ -17,8 +17,6 @@ import org.jetbrains.annotations.Nullable; import org.junit.After; import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.Arrays; @@ -48,7 +46,6 @@ import static org.junit.Assert.assertTrue; public class ChannelMembersIT extends ObjectsApiBaseIT { - private static final Logger LOG = LoggerFactory.getLogger(ChannelMembersIT.class); private static final String STATUS_01 = "myStatus01"; private static final String TYPE_01 = "myType01" + random(); private static final String TYPE_02 = "myType02" + random(); @@ -475,7 +472,7 @@ public void cleanUp() { .sync(); } catch (Exception e) { - LOG.warn("Could not cleanup {}", createdMembers, e); + System.out.printf("Could not cleanup %s%n", createdMembers); } } } diff --git a/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/objects/memberships/MembershipIT.java b/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/objects/memberships/MembershipIT.java index 2b17726406..c61d650bc0 100644 --- a/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/objects/memberships/MembershipIT.java +++ b/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/objects/memberships/MembershipIT.java @@ -14,8 +14,6 @@ import org.apache.http.HttpStatus; import org.junit.After; import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.Arrays; @@ -40,7 +38,6 @@ import static org.junit.Assert.assertNull; public class MembershipIT extends ObjectsApiBaseIT { - private static final Logger LOG = LoggerFactory.getLogger(MembershipIT.class); private static final String STATUS = "status"; private static final String CHANNEL = "channel"; @@ -453,7 +450,7 @@ public void cleanUp() { pubNubUnderTest.removeMemberships(channelIds).sync(); } catch (Exception e) { - LOG.warn("Could not cleanup {}", createdMembership, e); + System.out.printf("Could not cleanup {}", createdMembership); } } } diff --git a/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/objects/uuid/UUIDMetadataIT.java b/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/objects/uuid/UUIDMetadataIT.java index 556aff093b..7a8fe3ab3f 100644 --- a/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/objects/uuid/UUIDMetadataIT.java +++ b/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/objects/uuid/UUIDMetadataIT.java @@ -10,8 +10,6 @@ import org.apache.http.HttpStatus; import org.junit.After; import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.HashMap; @@ -33,7 +31,6 @@ import static org.junit.Assert.assertNotNull; public class UUIDMetadataIT extends ObjectsApiBaseIT { - private static final Logger LOG = LoggerFactory.getLogger(UUIDMetadataIT.class); private static final int NUMBER_OF_RANDOM_TEST_UUIDS = 10; private static final int FETCH_LIMIT = 3; @@ -184,7 +181,7 @@ public void cleanUp() { .uuid(pnSetUUIDMetadataResult.getData().getId()) .sync(); } catch (Exception e) { - LOG.warn("Could not cleanup {}", pnSetUUIDMetadataResult, e); + System.out.printf("Could not cleanup {}", pnSetUUIDMetadataResult, e); } }); } diff --git a/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/pam/AccessManagerIntegrationTest.java b/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/pam/AccessManagerIntegrationTest.java index 929f7ea3b9..350a99bb11 100644 --- a/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/pam/AccessManagerIntegrationTest.java +++ b/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/pam/AccessManagerIntegrationTest.java @@ -56,7 +56,7 @@ abstract class AccessManagerIntegrationTest extends BaseIntegrationTest { @Override protected void onPrePubNub() { - log.warn("onPrePubNub"); + System.out.println("onPrePubNub"); expectedChannel = randomChannel(); authKey = "auth_".concat(random()); authKey = authKey.toLowerCase(); @@ -71,7 +71,7 @@ protected void onBefore() { if (performOnServer()) { pubNub = server; } - log.warn("performOnServer: " + performOnServer()); + System.out.println("performOnServer: " + performOnServer()); if (addDelays) { pause(3); @@ -970,9 +970,9 @@ private void requestAccess(Integer... bitmasks) { } if (!revokeAllAccess) { - log.info(String.format("Requesting access for %1$s at %2$s level", sum, getPamLevel())); + System.out.println(String.format("Requesting access for %1$s at %2$s level", sum, getPamLevel())); } else { - log.info("Revoking all access!"); + System.out.println("Revoking all access!"); } final List bitList = Arrays.asList(bitmasks); @@ -1002,7 +1002,7 @@ private void requestAccess(Integer... bitmasks) { try { final PNAccessManagerGrantResult grantResult = grantOperationBuilder.sync(); assertNotNull(grantResult); - log.info(String.format("Access request result: %s", new Gson().toJson(grantResult))); + System.out.println(String.format("Access request result: %s", new Gson().toJson(grantResult))); if (revokeAllAccess) { assertEquals(LEVEL_APP, grantResult.getLevel()); } else { diff --git a/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/util/BaseIntegrationTest.java b/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/util/BaseIntegrationTest.java index 94e1808739..e30393c5b3 100644 --- a/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/util/BaseIntegrationTest.java +++ b/pubnub-gson/pubnub-gson-impl/src/integrationTest/java/com/pubnub/api/integration/util/BaseIntegrationTest.java @@ -43,8 +43,6 @@ public abstract class BaseIntegrationTest { - protected Logger log = LoggerFactory.getLogger(BaseIntegrationTest.class); - private static String SUB_KEY; private static String PUB_KEY; private static String PAM_SUB_KEY; @@ -149,7 +147,6 @@ private PNConfiguration getBasicPnConfiguration(@Nullable Consumer stringMessages = new ArrayList<>(); + public static final List logMessages = new ArrayList<>(); + + @Override + public String getName() { + return "CustomLoggerTestImpl"; + } + + @Override + public void info(String message) { + if (message != null) { + stringMessages.add(message); + } + } + + @Override + public void info(LogMessage logMessage) { + logMessages.add(logMessage); + } + + @Override + public void debug(String message) { + if (message != null) { + stringMessages.add(message); + } + } + + @Override + public void debug(LogMessage logMessage) { + logMessages.add(logMessage); + } + + public static void clear() { + stringMessages.clear(); + logMessages.clear(); + } +} diff --git a/pubnub-gson/pubnub-gson-impl/src/main/java/com/pubnub/internal/java/PubNubForJavaImpl.kt b/pubnub-gson/pubnub-gson-impl/src/main/java/com/pubnub/internal/java/PubNubForJavaImpl.kt index db298dbb0c..9d94e60332 100644 --- a/pubnub-gson/pubnub-gson-impl/src/main/java/com/pubnub/internal/java/PubNubForJavaImpl.kt +++ b/pubnub-gson/pubnub-gson-impl/src/main/java/com/pubnub/internal/java/PubNubForJavaImpl.kt @@ -67,6 +67,8 @@ import com.pubnub.api.java.v2.callbacks.EventListener import com.pubnub.api.java.v2.callbacks.StatusListener import com.pubnub.api.java.v2.endpoints.pubsub.PublishBuilder import com.pubnub.api.java.v2.endpoints.pubsub.SignalBuilder +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.internal.PubNubImpl import com.pubnub.internal.java.builder.PresenceBuilderImpl import com.pubnub.internal.java.builder.SubscribeBuilderImpl @@ -176,6 +178,15 @@ open class PubNubForJavaImpl(configuration: PNConfiguration) : } override fun history(): History { + logger.warn( + LogMessage( + message = LogMessageContent.Text( + "DEPRECATED: history() is deprecated. Use fetchMessages() instead." + ), + details = "This method will be removed in a future version", + location = this::class.java.simpleName + ) + ) return HistoryImpl(this) } @@ -197,6 +208,15 @@ open class PubNubForJavaImpl(configuration: PNConfiguration) : @Deprecated("Use {@link #grantToken(int)} instead.") override fun grantToken(): GrantTokenBuilder { + logger.warn( + LogMessage( + message = LogMessageContent.Text( + "DEPRECATED: grantToken() without TTL is deprecated. Use grantToken(int ttl) instead." + ), + details = "This method will be removed in a future version", + location = this::class.java.simpleName + ) + ) return GrantTokenImpl(this) } @@ -217,6 +237,15 @@ open class PubNubForJavaImpl(configuration: PNConfiguration) : } override fun publish(): Publish { + logger.warn( + LogMessage( + message = LogMessageContent.Text( + "DEPRECATED: publish() builder pattern is deprecated. Use publish(Object message, String channel) instead." + ), + details = "This method will be removed in a future version", + location = this::class.java.simpleName + ) + ) return PublishImpl(this) } @@ -225,6 +254,15 @@ open class PubNubForJavaImpl(configuration: PNConfiguration) : } override fun signal(): Signal { + logger.warn( + LogMessage( + message = LogMessageContent.Text( + "DEPRECATED: signal() builder pattern is deprecated. Use signal(Object message, String channel) instead." + ), + details = "This method will be removed in a future version", + location = this::class.java.simpleName + ) + ) return SignalImpl(this) } @@ -420,6 +458,15 @@ open class PubNubForJavaImpl(configuration: PNConfiguration) : } override fun fire(): Publish { + logger.warn( + LogMessage( + message = LogMessageContent.Text( + "DEPRECATED: fire() builder pattern is deprecated. Use fire(Object message, String channel) instead." + ), + details = "This method will be removed in a future version", + location = this::class.java.simpleName + ) + ) return publish().shouldStore(false).replicate(false) } diff --git a/pubnub-gson/pubnub-gson-impl/src/main/java/com/pubnub/internal/java/v2/PNConfigurationImpl.kt b/pubnub-gson/pubnub-gson-impl/src/main/java/com/pubnub/internal/java/v2/PNConfigurationImpl.kt index c75f9bf0ca..b92b477edf 100644 --- a/pubnub-gson/pubnub-gson-impl/src/main/java/com/pubnub/internal/java/v2/PNConfigurationImpl.kt +++ b/pubnub-gson/pubnub-gson-impl/src/main/java/com/pubnub/internal/java/v2/PNConfigurationImpl.kt @@ -6,13 +6,15 @@ import com.pubnub.api.enums.PNHeartbeatNotificationOptions import com.pubnub.api.enums.PNLogVerbosity import com.pubnub.api.java.v2.PNConfiguration import com.pubnub.api.java.v2.PNConfigurationOverride +import com.pubnub.api.logging.CustomLogger +import com.pubnub.api.logging.LogConfig import com.pubnub.api.retry.RetryConfiguration import com.pubnub.api.retry.RetryableEndpointGroup +import com.pubnub.internal.crypto.CryptoModuleImpl import okhttp3.Authenticator import okhttp3.CertificatePinner import okhttp3.ConnectionSpec import okhttp3.logging.HttpLoggingInterceptor -import org.slf4j.LoggerFactory import java.net.Proxy import java.net.ProxySelector import javax.net.ssl.HostnameVerifier @@ -71,6 +73,7 @@ class PNConfigurationImpl( ) ), override val managePresenceListManually: Boolean = false, + override val customLoggers: List? = null, ) : PNConfiguration { companion object { const val DEFAULT_DEDUPE_SIZE = 100 @@ -81,12 +84,26 @@ class PNConfigurationImpl( const val CONNECT_TIMEOUT = 5 } + // this method is used from cryptoModuleWithLogConfig using reflection + fun getCryptoModuleWithLogConfig(logConfig: LogConfig): CryptoModule? { + return cryptoModule?.let { module -> + if (module is CryptoModuleImpl) { + CryptoModuleImpl( + primaryCryptor = module.primaryCryptor, + cryptorsForDecryptionOnly = module.cryptorsForDecryptionOnly, + logConfig = logConfig + ) + } else { + // For custom implementations, return the original instance + module + } + } + } + class Builder internal constructor(defaultConfiguration: com.pubnub.api.v2.PNConfiguration) : PNConfiguration.Builder, PNConfigurationOverride.Builder { constructor(userId: UserId, subscribeKey: String) : this(PNConfigurationImpl(userId, subscribeKey)) - private val log = LoggerFactory.getLogger(this::class.simpleName) - override var userId: UserId = defaultConfiguration.userId override fun setUserId(userId: UserId): PNConfiguration.Builder { @@ -143,6 +160,15 @@ class PNConfigurationImpl( override var secure: Boolean = defaultConfiguration.secure + @Deprecated( + message = "LogVerbosity setting is deprecated and will be removed in future versions. " + + "For logging configuration:\n" + + "1. Use an SLF4J implementation (recommended)\n" + + "2. Or implement CustomLogger interface and set via customLoggers property. " + + "Use CustomLogger if your slf4j implementation like logback, log4j2, etc. can't meet " + + "your specific logging requirements.", + level = DeprecationLevel.WARNING + ) override fun logVerbosity(logVerbosity: PNLogVerbosity): Builder { this.logVerbosity = logVerbosity return this @@ -160,7 +186,7 @@ class PNConfigurationImpl( override fun presenceTimeout(presenceTimeout: Int): Builder { this.presenceTimeout = if (presenceTimeout < MINIMUM_PRESENCE_TIMEOUT) { - log.warn("Presence timeout is too low. Defaulting to: $MINIMUM_PRESENCE_TIMEOUT") + println("Presence timeout is too low. Defaulting to: $MINIMUM_PRESENCE_TIMEOUT") MINIMUM_PRESENCE_TIMEOUT } else { presenceTimeout @@ -291,6 +317,10 @@ class PNConfigurationImpl( override var certificatePinner: CertificatePinner? = defaultConfiguration.certificatePinner + @Deprecated( + message = "This setting is deprecated. Use customLoggers instead.", + level = DeprecationLevel.WARNING + ) override fun httpLoggingInterceptor(httpLoggingInterceptor: HttpLoggingInterceptor?): Builder { this.httpLoggingInterceptor = httpLoggingInterceptor return this @@ -368,6 +398,13 @@ class PNConfigurationImpl( override var managePresenceListManually: Boolean = defaultConfiguration.managePresenceListManually + override fun customLoggers(customLoggers: List?): Builder { + this.customLoggers = customLoggers + return this + } + + override var customLoggers: List? = defaultConfiguration.customLoggers + override fun build(): PNConfiguration { return PNConfigurationImpl( userId = userId, @@ -408,6 +445,7 @@ class PNConfigurationImpl( pnsdkSuffixes = pnsdkSuffixes, retryConfiguration = retryConfiguration, managePresenceListManually = managePresenceListManually, + customLoggers = customLoggers ) } } diff --git a/pubnub-gson/pubnub-gson-impl/src/test/kotlin/com/pubnub/internal/java/v2/subscription/SubscriptionSetImplTest.kt b/pubnub-gson/pubnub-gson-impl/src/test/kotlin/com/pubnub/internal/java/v2/subscription/SubscriptionSetImplTest.kt index 7a556b06fe..1bad279f06 100644 --- a/pubnub-gson/pubnub-gson-impl/src/test/kotlin/com/pubnub/internal/java/v2/subscription/SubscriptionSetImplTest.kt +++ b/pubnub-gson/pubnub-gson-impl/src/test/kotlin/com/pubnub/internal/java/v2/subscription/SubscriptionSetImplTest.kt @@ -1,5 +1,6 @@ package com.pubnub.internal.java.v2.subscription +import com.pubnub.api.logging.LogConfig import com.pubnub.api.v2.subscriptions.EmptyOptions import com.pubnub.api.v2.subscriptions.SubscriptionOptions import com.pubnub.internal.java.PubNubForJavaImpl @@ -23,6 +24,8 @@ class SubscriptionSetImplTest { @BeforeEach fun setUp() { + val testLogConfig = LogConfig("test-instance-id", "test-user-id") + every { pubNubImpl.logConfig } returns testLogConfig val listenerManager = ListenerManager(pubNubImpl) every { pubNubImpl.listenerManager } returns listenerManager diff --git a/pubnub-kotlin/pubnub-kotlin-core-api/src/commonMain/kotlin/com/pubnub/api/retry/RetryConfiguration.kt b/pubnub-kotlin/pubnub-kotlin-core-api/src/commonMain/kotlin/com/pubnub/api/retry/RetryConfiguration.kt index 0e4ee28504..174bcf3356 100644 --- a/pubnub-kotlin/pubnub-kotlin-core-api/src/commonMain/kotlin/com/pubnub/api/retry/RetryConfiguration.kt +++ b/pubnub-kotlin/pubnub-kotlin-core-api/src/commonMain/kotlin/com/pubnub/api/retry/RetryConfiguration.kt @@ -1,7 +1,6 @@ package com.pubnub.api.retry // import org.jetbrains.annotations.TestOnly TODO -// import org.slf4j.LoggerFactory TODO import kotlin.jvm.JvmSynthetic import kotlin.time.Duration import kotlin.time.Duration.Companion.seconds @@ -32,8 +31,6 @@ sealed class RetryConfiguration { val excludedOperations: List = emptyList(), isInternal: Boolean = false, ) : RetryConfiguration() { -// private val log = LoggerFactory.getLogger(this.javaClass.simpleName + "-" + "RetryConfiguration") - constructor( delayInSec: Int = MIN_DELAY, maxRetryNumber: Int = MAX_RETRIES, @@ -48,11 +45,9 @@ sealed class RetryConfiguration { init { if (!isInternal) { if (delayInSec < MIN_DELAY.seconds) { -// log.trace("Provided delay is less than $MIN_DELAY, setting it to $MIN_DELAY") delayInSec = MIN_DELAY.seconds } if (maxRetryNumber > MAX_RETRIES) { -// log.trace("Provided maxRetryNumber is greater than $MAX_RETRIES, setting it to $MAX_RETRIES") maxRetryNumber = MAX_RETRIES } } @@ -89,8 +84,6 @@ sealed class RetryConfiguration { val excludedOperations: List = emptyList(), isInternal: Boolean = false, ) : RetryConfiguration() { -// private val log = LoggerFactory.getLogger(this.javaClass.simpleName + "-" + "RetryConfiguration") - constructor( minDelayInSec: Int = MIN_DELAY, maxDelayInSec: Int = MAX_DELAY, @@ -125,7 +118,7 @@ sealed class RetryConfiguration { maxRetryNumber = maxRetryNumber.coerceAtMost(MAX_RETRIES) if (minDelayInSec != originalMinDelayInSec || maxDelayInSec != originalMaxDelayInSec || maxRetryNumber != originalMaxRetryNumber) { -// log.trace("Adjusted values: minDelayInSec=$minDelayInSec, maxDelayInSec=$maxDelayInSec, maxRetryNumber=$maxRetryNumber") + // no action } } } diff --git a/pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/crypto/CryptoModule.kt b/pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/crypto/CryptoModule.kt index 6fe8a26ffc..6106fae9db 100644 --- a/pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/crypto/CryptoModule.kt +++ b/pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/crypto/CryptoModule.kt @@ -1,6 +1,7 @@ package com.pubnub.api.crypto import com.pubnub.api.crypto.cryptor.Cryptor +import com.pubnub.api.logging.LogConfig import java.io.InputStream interface CryptoModule { @@ -16,7 +17,10 @@ interface CryptoModule { ): CryptoModule { return instantiateCryptoModuleImpl( primaryCryptor = instantiateLegacyCryptor(cipherKey, randomIv), - cryptorsForDecryptionOnly = listOf(instantiateLegacyCryptor(cipherKey, randomIv), instantiateAesCbcCryptor(cipherKey)), + cryptorsForDecryptionOnly = listOf( + instantiateLegacyCryptor(cipherKey, randomIv), + instantiateAesCbcCryptor(cipherKey) + ), ) } @@ -27,7 +31,10 @@ interface CryptoModule { ): CryptoModule { return instantiateCryptoModuleImpl( primaryCryptor = instantiateAesCbcCryptor(cipherKey), - cryptorsForDecryptionOnly = listOf(instantiateAesCbcCryptor(cipherKey), instantiateLegacyCryptor(cipherKey, randomIv)), + cryptorsForDecryptionOnly = listOf( + instantiateAesCbcCryptor(cipherKey), + instantiateLegacyCryptor(cipherKey, randomIv) + ), ) } @@ -52,10 +59,13 @@ private fun instantiateCryptoModuleImpl( primaryCryptor: Cryptor, cryptorsForDecryptionOnly: List, ): CryptoModule { - return Class.forName("com.pubnub.internal.crypto.CryptoModuleImpl").getConstructor(Cryptor::class.java, List::class.java).newInstance( - primaryCryptor, - cryptorsForDecryptionOnly, - ) as CryptoModule + return Class.forName("com.pubnub.internal.crypto.CryptoModuleImpl") + .getConstructor(Cryptor::class.java, List::class.java, LogConfig::class.java) + .newInstance( + primaryCryptor, + cryptorsForDecryptionOnly, + null + ) as CryptoModule } private fun instantiateLegacyCryptor( @@ -71,7 +81,8 @@ private fun instantiateLegacyCryptor( } private fun instantiateAesCbcCryptor(cipherKey: String): Cryptor { - return Class.forName("com.pubnub.internal.crypto.cryptor.AesCbcCryptor").getConstructor(String::class.java).newInstance( - cipherKey, - ) as Cryptor + return Class.forName("com.pubnub.internal.crypto.cryptor.AesCbcCryptor").getConstructor(String::class.java) + .newInstance( + cipherKey, + ) as Cryptor } diff --git a/pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/logging/CustomLogger.kt b/pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/logging/CustomLogger.kt new file mode 100644 index 0000000000..55b065ad05 --- /dev/null +++ b/pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/logging/CustomLogger.kt @@ -0,0 +1,82 @@ +package com.pubnub.api.logging + +/** + * Interface for custom logger implementations. + * Provides both string-based and structured LogMessage-based logging. + */ +interface CustomLogger { + /** + * The name of this logger implementation. + */ + val name: String get() = "CustomLogger" + + /** + * Log a trace message with a string. + */ + fun trace(message: String?) { + // Default implementation does nothing + } + + /** + * Log a trace message with structured data. + */ + fun trace(logMessage: LogMessage) { + // Default implementation does nothing + } + + /** + * Log a debug message with a string. + */ + fun debug(message: String?) { + // Default implementation does nothing + } + + /** + * Log a debug message with structured data. + */ + fun debug(logMessage: LogMessage) { + // Default implementation does nothing + } + + /** + * Log an info message with a string. + */ + fun info(message: String?) { + // Default implementation does nothing + } + + /** + * Log an info message with structured data. + */ + fun info(logMessage: LogMessage) { + // Default implementation does nothing + } + + /** + * Log a warning message with a string. + */ + fun warn(message: String?) { + // Default implementation does nothing + } + + /** + * Log a warning message with structured data. + */ + fun warn(logMessage: LogMessage) { + // Default implementation does nothing + } + + /** + * Log an error message with a string. + */ + fun error(message: String?) { + // Default implementation does nothing + } + + /** + * Log an error message with structured data. + */ + fun error(logMessage: LogMessage) { + // Default implementation does nothing + } +} diff --git a/pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/logging/LogConfig.kt b/pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/logging/LogConfig.kt new file mode 100644 index 0000000000..c93784b656 --- /dev/null +++ b/pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/logging/LogConfig.kt @@ -0,0 +1,10 @@ +package com.pubnub.api.logging + +/** + * Configuration for logging system with validation. + * + * @param pnInstanceId The PubNub instance identifier - must not be blank + * @param userId The user identifier - must not be blank + * @param customLoggers Optional list of custom loggers to use + */ +class LogConfig(val pnInstanceId: String, val userId: String, val customLoggers: List? = null) diff --git a/pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/logging/LogMessage.kt b/pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/logging/LogMessage.kt new file mode 100644 index 0000000000..6a147b82a7 --- /dev/null +++ b/pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/logging/LogMessage.kt @@ -0,0 +1,42 @@ +package com.pubnub.api.logging + +import com.google.gson.annotations.SerializedName +import org.slf4j.event.Level +import java.time.LocalTime +import java.time.format.DateTimeFormatter + +/** + * Represents a structured log message with validation and sanitization. + * + * @param pubNubId The PubNub instance identifier + * @param logLevel The logging level + * @param location The source location of the log + * @param type The type of log message (automatically inferred from message content) + * @param message The log message content + * @param details Optional additional details (will be sanitized) + * @param timestamp The timestamp when the log was created + */ +class LogMessage( + @SerializedName("message") + val message: LogMessageContent, + @SerializedName("details") + val details: String? = null, + @SerializedName("type") + val type: LogMessageType = message.inferType(), + @SerializedName("location") + val location: String? = null, // this value will be set in CompositeLogger if not set + @SerializedName("pubNubId") + val pubNubId: String? = null, // this value will be set in CompositeLogger + @SerializedName("logLevel") + val logLevel: Level? = null, // this value will be set in CompositeLogger + @SerializedName("timestamp") + val timestamp: String = LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss.SSS")), +) + +private fun LogMessageContent.inferType(): LogMessageType = when (this) { + is LogMessageContent.Text -> LogMessageType.TEXT + is LogMessageContent.Object -> LogMessageType.OBJECT + is LogMessageContent.Error -> LogMessageType.ERROR + is LogMessageContent.NetworkRequest -> LogMessageType.NETWORK_REQUEST + is LogMessageContent.NetworkResponse -> LogMessageType.NETWORK_RESPONSE +} diff --git a/pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/logging/LogMessageContent.kt b/pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/logging/LogMessageContent.kt new file mode 100644 index 0000000000..d3447ee442 --- /dev/null +++ b/pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/logging/LogMessageContent.kt @@ -0,0 +1,58 @@ +package com.pubnub.api.logging + +import com.google.gson.annotations.SerializedName + +/** + * Sealed class representing different types of log message content. + * This provides type safety when working with different message types. + */ +sealed class LogMessageContent { + /** + * Plain string message for text type logs. + */ + data class Text( + @SerializedName("message") + val message: String + ) : LogMessageContent() + + /** + * Dictionary/object message for object type logs. + */ + data class Object( + @SerializedName("message") + val message: Map + ) : LogMessageContent() + + /** + * Error message with type, message, and stack trace. + */ + data class Error( + @SerializedName("message") + val message: ErrorDetails + ) : LogMessageContent() + + /** + * Network request message. + */ + data class NetworkRequest( + @SerializedName("message") + val message: NetworkLog.Request + ) : LogMessageContent() + + /** + * Network response message. + */ + data class NetworkResponse( + @SerializedName("message") + val message: NetworkLog.Response + ) : LogMessageContent() +} + +data class ErrorDetails( + @SerializedName("type") + val type: String? = null, + @SerializedName("message") + val message: String, + @SerializedName("stack") + val stack: List? = null +) diff --git a/pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/logging/LogMessageType.kt b/pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/logging/LogMessageType.kt new file mode 100644 index 0000000000..c5a5ad5d04 --- /dev/null +++ b/pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/logging/LogMessageType.kt @@ -0,0 +1,9 @@ +package com.pubnub.api.logging + +enum class LogMessageType(val type: String) { + TEXT("text"), + OBJECT("object"), + ERROR("error"), + NETWORK_REQUEST("network-request"), + NETWORK_RESPONSE("network-response") +} diff --git a/pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/logging/NetworkLog.kt b/pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/logging/NetworkLog.kt new file mode 100644 index 0000000000..18650efcd4 --- /dev/null +++ b/pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/logging/NetworkLog.kt @@ -0,0 +1,19 @@ +package com.pubnub.api.logging + +import com.google.gson.annotations.SerializedName + +sealed class NetworkLog { + data class Request( + @SerializedName("message") + val message: NetworkRequestMessage, + @SerializedName("canceled") + val canceled: Boolean = false, + @SerializedName("failed") + val failed: Boolean = false + ) : NetworkLog() + + data class Response( + @SerializedName("message") + val message: NetworkResponseMessage + ) : NetworkLog() +} diff --git a/pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/logging/NetworkRequestMessage.kt b/pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/logging/NetworkRequestMessage.kt new file mode 100644 index 0000000000..99069d633c --- /dev/null +++ b/pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/logging/NetworkRequestMessage.kt @@ -0,0 +1,43 @@ +package com.pubnub.api.logging + +import com.google.gson.annotations.SerializedName + +data class NetworkRequestMessage( + @SerializedName("origin") + val origin: String, + @SerializedName("path") + val path: String, + @SerializedName("query") + val query: Map? = null, + @SerializedName("method") + val method: HttpMethod, + @SerializedName("headers") + val headers: Map? = null, + @SerializedName("formData") + val formData: Map? = null, + @SerializedName("body") + val body: String? = null, + @SerializedName("timeout") + val timeout: Long? = null, + @SerializedName("identifier") + val identifier: String? = null +) + +enum class HttpMethod(val value: String) { + GET("get"), + POST("post"), + PATCH("patch"), + DELETE("delete"); + + companion object { + fun fromString(method: String): HttpMethod { + return when (method.lowercase()) { + "get" -> GET + "post" -> POST + "patch" -> PATCH + "delete" -> DELETE + else -> throw IllegalStateException("Unknown HTTP method: $method") + } + } + } +} diff --git a/pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/logging/NetworkResponseMessage.kt b/pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/logging/NetworkResponseMessage.kt new file mode 100644 index 0000000000..a75f426752 --- /dev/null +++ b/pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/logging/NetworkResponseMessage.kt @@ -0,0 +1,14 @@ +package com.pubnub.api.logging + +import com.google.gson.annotations.SerializedName + +data class NetworkResponseMessage( + @SerializedName("url") + val url: String, + @SerializedName("status") + val status: Int, + @SerializedName("headers") + val headers: Map? = null, + @SerializedName("body") + val body: String? = null +) diff --git a/pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/v2/PNConfiguration.kt b/pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/v2/PNConfiguration.kt index af2d5c353a..1afd8174f5 100644 --- a/pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/v2/PNConfiguration.kt +++ b/pubnub-kotlin/pubnub-kotlin-core-api/src/jvmMain/kotlin/com/pubnub/api/v2/PNConfiguration.kt @@ -4,6 +4,7 @@ import com.pubnub.api.UserId import com.pubnub.api.crypto.CryptoModule import com.pubnub.api.enums.PNHeartbeatNotificationOptions import com.pubnub.api.enums.PNLogVerbosity +import com.pubnub.api.logging.CustomLogger import com.pubnub.api.retry.RetryConfiguration import okhttp3.Authenticator import okhttp3.CertificatePinner @@ -77,6 +78,13 @@ actual interface PNConfiguration { /** * Set to [PNLogVerbosity.BODY] to enable logging of network traffic, otherwise se to [PNLogVerbosity.NONE]. */ + @Deprecated( + message = "LogVerbosity setting is deprecated and will be removed in future versions. " + + "For logging configuration:\n" + + "1. Use an SLF4J implementation (recommended)\n" + + "2. Or implement CustomLogger interface and set via customLoggers property", + level = DeprecationLevel.WARNING + ) actual val logVerbosity: PNLogVerbosity /** @@ -124,7 +132,7 @@ actual interface PNConfiguration { * For non subscribe operations (publish, herenow, etc), * This property relates to a read timeout that is applied from the moment the connection between a client * and the server has been successfully established. It defines a maximum time of inactivity between two - * data packets when waiting for the server’s response. + * data packets when waiting for the server's response. * * The value is in seconds. * @@ -141,7 +149,7 @@ actual interface PNConfiguration { * For non subscribe operations (publish, herenow, etc), * This property relates to a read timeout that is applied from the moment the connection between a client * and the server has been successfully established. It defines a maximum time of inactivity between two - * data packets when waiting for the server’s response. + * data packets when waiting for the server's response. * * The value is in seconds. * @@ -234,6 +242,10 @@ actual interface PNConfiguration { * * @see [HttpLoggingInterceptor] */ + @Deprecated( + message = "This setting is deprecated. Use customLoggers instead.", + level = DeprecationLevel.WARNING + ) val httpLoggingInterceptor: HttpLoggingInterceptor? /** @@ -287,6 +299,12 @@ actual interface PNConfiguration { */ val managePresenceListManually: Boolean + /** + * Custom loggers list for creating additional logger instances. + * Use it if your slf4j implementation like logback, log4j2, etc. can't meet your specific logging requirements. + */ + val customLoggers: List? + @Deprecated( level = DeprecationLevel.WARNING, message = """Use UserId instead e.g. config.userId.value""", @@ -381,6 +399,15 @@ actual interface PNConfiguration { /** * Set to [PNLogVerbosity.BODY] to enable logging of network traffic, otherwise se to [PNLogVerbosity.NONE]. */ + @Deprecated( + message = "LogVerbosity setting is deprecated and will be removed in future versions. " + + "For logging configuration:\n" + + "1. Use an SLF4J implementation (recommended)\n" + + "2. Or implement CustomLogger interface and set via customLoggers property. " + + "Use CustomLogger if your slf4j implementation like logback, log4j2, etc. can't meet " + + "your specific logging requirements.", + level = DeprecationLevel.WARNING + ) var logVerbosity: PNLogVerbosity /** @@ -428,7 +455,7 @@ actual interface PNConfiguration { * For non subscribe operations (publish, herenow, etc), * This property relates to a read timeout that is applied from the moment the connection between a client * and the server has been successfully established. It defines a maximum time of inactivity between two - * data packets when waiting for the server’s response. + * data packets when waiting for the server's response. * * The value is in seconds. * @@ -448,7 +475,7 @@ actual interface PNConfiguration { * For non subscribe operations (publish, herenow, etc), * This property relates to a read timeout that is applied from the moment the connection between a client * and the server has been successfully established. It defines a maximum time of inactivity between two - * data packets when waiting for the server’s response. + * data packets when waiting for the server's response. * * The value is in seconds. * @@ -541,6 +568,10 @@ actual interface PNConfiguration { * * @see [HttpLoggingInterceptor] */ + @Deprecated( + message = "This setting is deprecated. Use customLoggers instead", + level = DeprecationLevel.WARNING + ) var httpLoggingInterceptor: HttpLoggingInterceptor? /** @@ -578,7 +609,7 @@ actual interface PNConfiguration { * Retry configuration for requests. * Defaults to [RetryConfiguration.Exponential] enabled only for subscription endpoint (other endpoints are excluded). * - * Use [RetryConfiguration.Linear] to set retry with linear delay intervar + * Use [RetryConfiguration.Linear] to set retry with linear delay interval * Use [RetryConfiguration.Exponential] to set retry with exponential delay interval * Delay will vary from provided value by random value. */ @@ -594,6 +625,12 @@ actual interface PNConfiguration { */ var managePresenceListManually: Boolean + /** + * Custom loggers list for creating additional logger instances. + * Use it if your slf4j implementation like logback, log4j2, etc. can't meet your specific logging requirements. + */ + var customLoggers: List? + /** * Create a [PNConfiguration] object with values from this builder. */ @@ -693,7 +730,7 @@ interface PNConfigurationOverride { * For non subscribe operations (publish, herenow, etc), * This property relates to a read timeout that is applied from the moment the connection between a client * and the server has been successfully established. It defines a maximum time of inactivity between two - * data packets when waiting for the server’s response. + * data packets when waiting for the server's response. * * The value is in seconds. * diff --git a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/appContext/GetAllUUIDMetadataMain.kt b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/appContext/GetAllUUIDMetadataMain.kt index da2eb8de99..af738669dd 100644 --- a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/appContext/GetAllUUIDMetadataMain.kt +++ b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/appContext/GetAllUUIDMetadataMain.kt @@ -5,7 +5,6 @@ package com.pubnub.docs.appContext import com.pubnub.api.PubNub import com.pubnub.api.UserId -import com.pubnub.api.enums.PNLogVerbosity import com.pubnub.api.v2.PNConfiguration /** @@ -22,7 +21,6 @@ fun main() { val userId = UserId("uuid-metadata-demo-user") val config = PNConfiguration.builder(userId, "demo").apply { publishKey = "demo" - logVerbosity = PNLogVerbosity.BODY // Enable debug logging of network calls }.build() // 2. Create PubNub instance diff --git a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/configuration/ConfigurationMain.kt b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/configuration/ConfigurationMain.kt index be9a34ef50..78c81eb75f 100644 --- a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/configuration/ConfigurationMain.kt +++ b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/configuration/ConfigurationMain.kt @@ -4,7 +4,6 @@ package com.pubnub.docs.configuration import com.pubnub.api.UserId import com.pubnub.api.crypto.CryptoModule import com.pubnub.api.enums.PNHeartbeatNotificationOptions -import com.pubnub.api.enums.PNLogVerbosity import com.pubnub.api.retry.RetryConfiguration import com.pubnub.api.v2.PNConfiguration @@ -69,7 +68,6 @@ fun createAdvancedConfig(): PNConfiguration { suppressLeaveEvents = false // Whether to send leave events when disconnecting // Debugging parameters - logVerbosity = PNLogVerbosity.BODY // Enable debug logging of network calls // Retry configuration (for reconnection) retryConfiguration = RetryConfiguration.Linear( diff --git a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/entities/ChannelGroupMain.kt b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/entities/ChannelGroupMain.kt index a9dd704969..cdd962cfac 100644 --- a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/entities/ChannelGroupMain.kt +++ b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/entities/ChannelGroupMain.kt @@ -4,7 +4,6 @@ package com.pubnub.docs.entities // snippet.channelGroup import com.pubnub.api.PubNub import com.pubnub.api.UserId -import com.pubnub.api.enums.PNLogVerbosity import com.pubnub.api.v2.PNConfiguration import com.pubnub.api.v2.entities.ChannelGroup @@ -17,7 +16,6 @@ fun main() { val config = PNConfiguration.builder(userId, "demo").apply { publishKey = "demo" subscribeKey = "demo" - logVerbosity = PNLogVerbosity.BODY // Enable debug logging of network calls }.build() // 2. Create PubNub instance diff --git a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/entities/ChannelMain.kt b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/entities/ChannelMain.kt index 97be211ce8..afc3f03d08 100644 --- a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/entities/ChannelMain.kt +++ b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/entities/ChannelMain.kt @@ -4,7 +4,6 @@ package com.pubnub.docs.entities // snippet.channelMain import com.pubnub.api.PubNub import com.pubnub.api.UserId -import com.pubnub.api.enums.PNLogVerbosity import com.pubnub.api.v2.PNConfiguration fun main() { @@ -16,7 +15,6 @@ fun main() { val config = PNConfiguration.builder(userId, "demo").apply { publishKey = "demo" subscribeKey = "demo" - logVerbosity = PNLogVerbosity.BODY // Enable debug logging of network calls }.build() // 2. Create PubNub instance diff --git a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/entities/ChannelMetadataMain.kt b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/entities/ChannelMetadataMain.kt index 9ba350334c..9f9792a592 100644 --- a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/entities/ChannelMetadataMain.kt +++ b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/entities/ChannelMetadataMain.kt @@ -4,7 +4,6 @@ package com.pubnub.docs.entities // snippet.channelMetadata import com.pubnub.api.PubNub import com.pubnub.api.UserId -import com.pubnub.api.enums.PNLogVerbosity import com.pubnub.api.v2.PNConfiguration import com.pubnub.api.v2.entities.ChannelMetadata @@ -17,7 +16,6 @@ fun main() { val config = PNConfiguration.builder(userId, "demo").apply { publishKey = "demo" subscribeKey = "demo" - logVerbosity = PNLogVerbosity.BODY // Enable debug logging of network calls }.build() // 2. Create PubNub instance diff --git a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/entities/UserMetadata.kt b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/entities/UserMetadata.kt index 18ad960293..ca19f3f774 100644 --- a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/entities/UserMetadata.kt +++ b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/entities/UserMetadata.kt @@ -4,7 +4,6 @@ package com.pubnub.docs.entities // snippet.userMetadata import com.pubnub.api.PubNub import com.pubnub.api.UserId -import com.pubnub.api.enums.PNLogVerbosity import com.pubnub.api.v2.PNConfiguration fun main() { @@ -16,7 +15,6 @@ fun main() { val config = PNConfiguration.builder(userId, "demo").apply { publishKey = "demo" subscribeKey = "demo" - logVerbosity = PNLogVerbosity.BODY // Enable debug logging of network calls }.build() // 2. Create PubNub instance diff --git a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/fileSharing/FileSharingMain.kt b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/fileSharing/FileSharingMain.kt index 2de4432e65..263c36732d 100644 --- a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/fileSharing/FileSharingMain.kt +++ b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/fileSharing/FileSharingMain.kt @@ -4,7 +4,6 @@ package com.pubnub.docs.fileSharing // snippet.filesBasicUsage import com.pubnub.api.PubNub import com.pubnub.api.UserId -import com.pubnub.api.enums.PNLogVerbosity import com.pubnub.api.v2.PNConfiguration import java.io.File import java.io.FileInputStream @@ -24,7 +23,6 @@ fun main() { val userId = UserId("file-upload-demo-user") val config = PNConfiguration.builder(userId, "demo").apply { publishKey = "demo" - logVerbosity = PNLogVerbosity.BODY // Enable debug logging of network calls }.build() // 2. Create PubNub instance diff --git a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/logging/LogginExampleMain.kt b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/logging/LogginExampleMain.kt index 80a0d2a36d..ee37f3c5cf 100644 --- a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/logging/LogginExampleMain.kt +++ b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/logging/LogginExampleMain.kt @@ -4,31 +4,20 @@ package com.pubnub.docs.logging // snippet.loggingExampleMain import com.pubnub.api.PubNub import com.pubnub.api.UserId -import com.pubnub.api.enums.PNLogVerbosity import com.pubnub.api.v2.PNConfiguration fun main() { println("PubNub Logging Example") println("======================") - // Configure PubNub with logging enabled val userId = UserId("loggingDemoUser") val pnConfiguration = PNConfiguration.builder(userId, "demo").apply { // Replace "demo" with your Subscribe Key from the PubNub Admin Portal publishKey = "demo" // Replace with your Publish Key from the PubNub Admin Portal - - // Set log verbosity - configure how much detail to log - // Options: - // - PNLogVerbosity.NONE (Turn off logging) - // - PNLogVerbosity.BODY (Log request and response bodies - most detailed) - logVerbosity = PNLogVerbosity.BODY }.build() - println("Logging configured with level: ${pnConfiguration.logVerbosity}") - // Initialize PubNub with the configuration val pubnub = PubNub.create(pnConfiguration) - println("PubNub initialized with logging enabled") // Perform operations to generate logs demonstrateLogging(pubnub) @@ -83,6 +72,5 @@ fun demonstrateLogging(pubnub: PubNub) { } println("\nLogging demonstration complete") - println("Check your console for detailed logs based on the configured verbosity level") } // snippet.end diff --git a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/logging/LoggingLog4j2Main.kt b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/logging/LoggingLog4j2Main.kt index 853b38e569..36b565483b 100644 --- a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/logging/LoggingLog4j2Main.kt +++ b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/logging/LoggingLog4j2Main.kt @@ -3,7 +3,6 @@ package com.pubnub.docs.logging import com.pubnub.api.PubNub import com.pubnub.api.PubNubException import com.pubnub.api.UserId -import com.pubnub.api.enums.PNLogVerbosity import com.pubnub.api.v2.PNConfiguration import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.Logger @@ -13,28 +12,17 @@ object LoggingLog4j2 { @JvmStatic fun main(args: Array) { - // Configure PubNub with logging enabled - logger.info("Initializing PubNub with logging enabled") - val config = PNConfiguration.builder( UserId("log4jDemoUser"), "demo" // Replace with your Subscribe Key from the PubNub Admin Portal ) { // Add publish key (only required if publishing) publishKey = "demo" // Replace with your Publish Key from the PubNub Admin Portal - // Set log verbosity to BODY to see detailed logs - logVerbosity = PNLogVerbosity.BODY - // in log4j2.xml configure specific logger for PubNub network calls e.g. - // - // - // } // Initialize PubNub with the configuration val pubnub = PubNub.create(config.build()) - logger.info("PubNub client initialized with BODY level logging") - // Perform some operations to generate logs try { // Get time operation diff --git a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/logging/LoggingLogbackMain.kt b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/logging/LoggingLogbackMain.kt index c01868cddf..d391dd4260 100644 --- a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/logging/LoggingLogbackMain.kt +++ b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/logging/LoggingLogbackMain.kt @@ -5,7 +5,6 @@ package com.pubnub.docs.logging import com.pubnub.api.PubNub import com.pubnub.api.PubNubException import com.pubnub.api.UserId -import com.pubnub.api.enums.PNLogVerbosity import com.pubnub.api.v2.PNConfiguration import org.slf4j.Logger import org.slf4j.LoggerFactory @@ -18,7 +17,6 @@ object LoggingLogback { fun main(args: Array) { logger.info("Starting PubNub logging example...") - // Configure PubNub with logging enabled val config = PNConfiguration.builder( UserId("loggingDemoUser"), "demo" // Replace with your Subscribe Key from the PubNub Admin Portal @@ -26,13 +24,6 @@ object LoggingLogback { // Add publish key (only required if publishing) publishKey = "demo" // Replace with your Publish Key from the PubNub Admin Portal - // Set log verbosity - options are: - // NONE - Turn off logging - // BODY - Log request and response bodies - logVerbosity = PNLogVerbosity.BODY - // in logback.xml configure specific logger for PubNub network calls e.g. - // - // Other optional configurations secure = true } @@ -40,8 +31,6 @@ object LoggingLogback { // Initialize PubNub with the configuration val pubnub = PubNub.create(config.build()) - logger.info("PubNub client initialized with BODY level logging") - // Perform some operations to generate logs try { // Get time operation will generate logs diff --git a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/logging/LoggingSlf4jSimpleMain.kt b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/logging/LoggingSlf4jSimpleMain.kt index 512cfd5ebf..6682c75b5c 100644 --- a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/logging/LoggingSlf4jSimpleMain.kt +++ b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/logging/LoggingSlf4jSimpleMain.kt @@ -5,7 +5,6 @@ package com.pubnub.docs.logging import com.pubnub.api.PubNub import com.pubnub.api.PubNubException import com.pubnub.api.UserId -import com.pubnub.api.enums.PNLogVerbosity import com.pubnub.api.v2.PNConfiguration import org.slf4j.Logger import org.slf4j.LoggerFactory @@ -15,24 +14,17 @@ object LoggingSlf4jSimpl { @JvmStatic fun main(args: Array) { - // Configure PubNub with logging enabled - logger.info("Initializing PubNub with logging enabled") - val config = PNConfiguration.builder( UserId("slf4jSimpleDemoUser"), "demo" // Replace with your Subscribe Key from the PubNub Admin Portal ) { // Add publish key (only required if publishing) publishKey = "demo" // Replace with your Publish Key from the PubNub Admin Portal - // Set log verbosity to BODY to see detailed logs - logVerbosity = PNLogVerbosity.BODY } // Initialize PubNub with the configuration val pubnub = PubNub.create(config.build()) - logger.info("PubNub client initialized with BODY level logging") - // Perform some operations to generate logs try { // Get time operation diff --git a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/messagePersistence/FetchMessagesMain.kt b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/messagePersistence/FetchMessagesMain.kt index 6daf41922e..36453f60eb 100644 --- a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/messagePersistence/FetchMessagesMain.kt +++ b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/messagePersistence/FetchMessagesMain.kt @@ -4,7 +4,6 @@ package com.pubnub.docs.messagePersistence // snippet.fetchMessages import com.pubnub.api.PubNub import com.pubnub.api.UserId -import com.pubnub.api.enums.PNLogVerbosity import com.pubnub.api.models.consumer.PNBoundedPage import com.pubnub.api.models.consumer.history.PNFetchMessagesResult import com.pubnub.api.v2.PNConfiguration @@ -21,7 +20,6 @@ fun main() { val userId = UserId("history-demo-user") val config = PNConfiguration.builder(userId, "demo").apply { publishKey = "demo" - logVerbosity = PNLogVerbosity.BODY // Enable network calls logging }.build() // Create PubNub instance diff --git a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/messageReactions/MessageReactionWithPagingMain.kt b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/messageReactions/MessageReactionWithPagingMain.kt index 26e60f05b0..963d85f632 100644 --- a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/messageReactions/MessageReactionWithPagingMain.kt +++ b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/messageReactions/MessageReactionWithPagingMain.kt @@ -5,7 +5,6 @@ package com.pubnub.docs.messageReactions import com.pubnub.api.PubNub import com.pubnub.api.PubNubException import com.pubnub.api.UserId -import com.pubnub.api.enums.PNLogVerbosity import com.pubnub.api.models.consumer.PNBoundedPage import com.pubnub.api.models.consumer.message_actions.PNGetMessageActionsResult import com.pubnub.api.models.consumer.message_actions.PNMessageAction @@ -15,7 +14,6 @@ fun main() { val userId = UserId("message-action-demo-user") val config = PNConfiguration.builder(userId, "demo").apply { publishKey = "demo" - logVerbosity = PNLogVerbosity.BODY // Enable debug logging for visibility }.build() val pubnub = PubNub.create(config) diff --git a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/messageReactions/MessageReactionsMain.kt b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/messageReactions/MessageReactionsMain.kt index 1a585ebbba..ae970e4859 100644 --- a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/messageReactions/MessageReactionsMain.kt +++ b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/messageReactions/MessageReactionsMain.kt @@ -4,7 +4,6 @@ package com.pubnub.docs.messageReactions // snippet.messageReactionsMain import com.pubnub.api.PubNub import com.pubnub.api.UserId -import com.pubnub.api.enums.PNLogVerbosity import com.pubnub.api.models.consumer.message_actions.PNMessageAction import com.pubnub.api.v2.PNConfiguration @@ -16,7 +15,6 @@ fun main() { val userId = UserId("message-action-demo-user") val config = PNConfiguration.builder(userId, "demo").apply { publishKey = "demo" - logVerbosity = PNLogVerbosity.BODY // Enable debug logging of network calls }.build() // 2. Create PubNub instance diff --git a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/miscellaneous/CreatePushPayloadMain.kt b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/miscellaneous/CreatePushPayloadMain.kt index ec9c322a97..449f425065 100644 --- a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/miscellaneous/CreatePushPayloadMain.kt +++ b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/miscellaneous/CreatePushPayloadMain.kt @@ -4,7 +4,6 @@ package com.pubnub.docs.miscellaneous // snippet.createPushPayloadMain import com.pubnub.api.PubNub import com.pubnub.api.UserId -import com.pubnub.api.enums.PNLogVerbosity import com.pubnub.api.enums.PNPushEnvironment import com.pubnub.api.models.consumer.push.payload.PushPayloadHelper import com.pubnub.api.v2.PNConfiguration @@ -26,7 +25,6 @@ fun main() { val userId = UserId("push-helper-demo-user") val config = PNConfiguration.builder(userId, "demo").apply { publishKey = "demo" - logVerbosity = PNLogVerbosity.BODY // Enable debug logging of network calls }.build() // 2. Create PubNub instance diff --git a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/mobilePush/AddPushNotificationsOnChannelsMain.kt b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/mobilePush/AddPushNotificationsOnChannelsMain.kt index f386f2da09..aa1506d27f 100644 --- a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/mobilePush/AddPushNotificationsOnChannelsMain.kt +++ b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/mobilePush/AddPushNotificationsOnChannelsMain.kt @@ -2,7 +2,6 @@ package com.pubnub.docs.mobilePush import com.pubnub.api.PubNub import com.pubnub.api.UserId -import com.pubnub.api.enums.PNLogVerbosity import com.pubnub.api.enums.PNPushEnvironment import com.pubnub.api.enums.PNPushType import com.pubnub.api.models.consumer.PNPublishResult @@ -30,7 +29,6 @@ fun main() { val userId = UserId("push-notifications-demo-user") val config = PNConfiguration.builder(userId, "demo").apply { publishKey = "demo" - logVerbosity = PNLogVerbosity.BODY // Enable debug logging of network calls }.build() // 2. Create PubNub instance diff --git a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/presence/HereNowMain.kt b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/presence/HereNowMain.kt index 7e7f6ccf85..899ca616e9 100644 --- a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/presence/HereNowMain.kt +++ b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/presence/HereNowMain.kt @@ -4,7 +4,6 @@ package com.pubnub.docs.presence import com.pubnub.api.PubNub import com.pubnub.api.UserId -import com.pubnub.api.enums.PNLogVerbosity import com.pubnub.api.v2.PNConfiguration fun main() { @@ -15,7 +14,6 @@ fun main() { val userId = UserId("here-now-demo-user") val config = PNConfiguration.builder(userId, "demo").apply { publishKey = "demo" - logVerbosity = PNLogVerbosity.BODY // Enable debug logging of network calls }.build() // Create PubNub instance diff --git a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/publishAndSubscribe/publish/PublishMain.kt b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/publishAndSubscribe/publish/PublishMain.kt index 42bf8c1690..8e2f3672f8 100644 --- a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/publishAndSubscribe/publish/PublishMain.kt +++ b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/publishAndSubscribe/publish/PublishMain.kt @@ -3,7 +3,6 @@ package com.pubnub.docs.publishAndSubscribe.publish // snippet.publishMain import com.pubnub.api.PubNub import com.pubnub.api.UserId -import com.pubnub.api.enums.PNLogVerbosity import com.pubnub.api.v2.PNConfiguration fun main() { @@ -14,7 +13,6 @@ fun main() { val userId = UserId("publish-demo-user") val config = PNConfiguration.builder(userId, "demo").apply { publishKey = "demo" - logVerbosity = PNLogVerbosity.BODY // Enable debug logging of network calls }.build() // Create PubNub instance diff --git a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/publishAndSubscribe/subscribe/SubscribeOld.kt b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/publishAndSubscribe/subscribe/SubscribeOld.kt index 18ff0abf99..b1f3d018aa 100644 --- a/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/publishAndSubscribe/subscribe/SubscribeOld.kt +++ b/pubnub-kotlin/pubnub-kotlin-docs/src/main/kotlin/com/pubnub/docs/publishAndSubscribe/subscribe/SubscribeOld.kt @@ -3,7 +3,6 @@ package com.pubnub.docs.publishAndSubscribe.subscribe import com.pubnub.api.PubNub import com.pubnub.api.UserId import com.pubnub.api.callbacks.SubscribeCallback -import com.pubnub.api.enums.PNLogVerbosity import com.pubnub.api.enums.PNStatusCategory import com.pubnub.api.models.consumer.PNStatus import com.pubnub.api.models.consumer.pubsub.PNPresenceEventResult @@ -17,7 +16,6 @@ class SubscribeOld : SnippetBase() { // snippet.subscribeWithLogging val pnConfiguration = com.pubnub.api.v2.PNConfiguration.builder(UserId("myUserId"), "demo").apply { publishKey = "my_pubkey" - logVerbosity = PNLogVerbosity.BODY } val pubnub = PubNub.create(pnConfiguration.build()) diff --git a/pubnub-kotlin/pubnub-kotlin-impl/build.gradle.kts b/pubnub-kotlin/pubnub-kotlin-impl/build.gradle.kts index f784165af8..87b2ea090d 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/build.gradle.kts +++ b/pubnub-kotlin/pubnub-kotlin-impl/build.gradle.kts @@ -49,8 +49,6 @@ dependencies { implementation(libs.cbor) testImplementation(libs.wiremock) - testImplementation(libs.logback.classic) - testImplementation(libs.logback.core) testImplementation(libs.cucumber.java) testImplementation(libs.cucumber.junit) testImplementation(libs.cucumber.picocontainer) diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/integrationTest/kotlin/com/pubnub/api/integration/BaseIntegrationTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/integrationTest/kotlin/com/pubnub/api/integration/BaseIntegrationTest.kt index 20a33dc71f..3113aad141 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/integrationTest/kotlin/com/pubnub/api/integration/BaseIntegrationTest.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/integrationTest/kotlin/com/pubnub/api/integration/BaseIntegrationTest.kt @@ -5,18 +5,15 @@ import com.pubnub.api.UserId import com.pubnub.api.enums.PNLogVerbosity import com.pubnub.api.retry.RetryConfiguration import com.pubnub.api.v2.PNConfiguration -import com.pubnub.test.CommonUtils.createInterceptor import com.pubnub.test.Keys +import okhttp3.logging.HttpLoggingInterceptor import org.junit.After import org.junit.Before import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach -import org.slf4j.LoggerFactory import java.util.UUID abstract class BaseIntegrationTest { - protected val logger = LoggerFactory.getLogger(this.javaClass.simpleName) - val pubnub: PubNub by lazy { createPubNub() } val server: PubNub by lazy { createServer() } var clientConfig: PNConfiguration.Builder.() -> Unit = {} @@ -95,7 +92,6 @@ abstract class BaseIntegrationTest { } clientConfig.retryConfiguration = RetryConfiguration.None clientConfig.logVerbosity = PNLogVerbosity.NONE - clientConfig.httpLoggingInterceptor = createInterceptor(logger) return clientConfig } @@ -105,7 +101,7 @@ abstract class BaseIntegrationTest { serverConfig.publishKey = Keys.pamPubKey serverConfig.secretKey = Keys.pamSecKey serverConfig.logVerbosity = PNLogVerbosity.NONE - serverConfig.httpLoggingInterceptor = createInterceptor(logger) + serverConfig.httpLoggingInterceptor = HttpLoggingInterceptor() serverConfig.action() return serverConfig.build() diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/integrationTest/kotlin/com/pubnub/api/integration/LoggingIntegrationTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/integrationTest/kotlin/com/pubnub/api/integration/LoggingIntegrationTest.kt new file mode 100644 index 0000000000..b8ae78e9e5 --- /dev/null +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/integrationTest/kotlin/com/pubnub/api/integration/LoggingIntegrationTest.kt @@ -0,0 +1,114 @@ +package com.pubnub.api.integration + +import com.pubnub.api.PubNub +import com.pubnub.api.UserId +import com.pubnub.api.logging.CustomLogger +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent +import com.pubnub.api.logging.LogMessageType +import com.pubnub.api.v2.PNConfiguration +import com.pubnub.test.CommonUtils.generatePayload +import com.pubnub.test.CommonUtils.randomChannel +import com.pubnub.test.Keys +import org.junit.Assert.assertTrue +import org.junit.Test + +class LoggingIntegrationTest : BaseIntegrationTest() { + @Test + fun testCanLogMessagesUsingCustomLogger() { + // Clear any previous messages + CustomLoggerTestImpl.clear() + + val expectedUuid = PubNub.generateUUID() + val configBuilder = PNConfiguration.builder(UserId(expectedUuid), Keys.subKey) { + publishKey = Keys.pubKey + customLoggers = listOf(CustomLoggerTestImpl()) + } + val pubNub = PubNub.create(configBuilder.build()) + + val expectedChannel = randomChannel() + pubNub.publish( + channel = expectedChannel, + message = generatePayload(), + customMessageType = "myType" + ).sync() + + // Verify logging + assertTrue("Should have received string messages", CustomLoggerTestImpl.stringMessages.isNotEmpty()) + assertTrue("Should have received LogMessage objects", CustomLoggerTestImpl.logMessages.isNotEmpty()) + + // Verify content + assertTrue( + "Should have called publish on the expected channel", + CustomLoggerTestImpl.stringMessages.any { msg -> + msg.contains("PublishEndpoint") && msg.contains(expectedChannel) + } + ) + + assertTrue( + "Should have called publish on the expected channel", + CustomLoggerTestImpl.stringMessages.any { msg -> + msg.contains("NetworkRequest") && msg.contains(expectedChannel) + } + ) + + assertTrue( + "Should have called publish on the expected channel", + CustomLoggerTestImpl.stringMessages.any { msg -> + msg.contains("NetworkResponse") && msg.contains(expectedChannel) + } + ) + + assertTrue( + "Should have called publish on the expected channel", + CustomLoggerTestImpl.logMessages.any { msg -> + msg.type == LogMessageType.OBJECT && msg.location!!.contains("PublishEndpoint") && + (msg.message as? LogMessageContent.Object)?.message?.get("channel") == expectedChannel + } + ) + + assertTrue( + "Should have called publish API. LogMessage type should be NETWORK_REQUEST", + CustomLoggerTestImpl.logMessages.any { msg -> + msg.type == LogMessageType.NETWORK_REQUEST && msg.location!!.contains("publish") + } + ) + + assertTrue( + "Should have called publish API. LogMessage type should be NETWORK_RESPONSE", + CustomLoggerTestImpl.logMessages.any { msg -> + msg.type == LogMessageType.NETWORK_RESPONSE && msg.location!!.contains("publish") + } + ) + } + + class CustomLoggerTestImpl : CustomLogger { + override val name: String = "CustomLoggerTestImpl" + + override fun trace(message: String?) { + stringMessages.add(message ?: "") + } + + override fun trace(message: LogMessage) { + logMessages.add(message) + } + + override fun debug(message: String?) { + stringMessages.add(message ?: "") + } + + override fun debug(logMessage: LogMessage) { + logMessages.add(logMessage) + } + + companion object { + val stringMessages = mutableListOf() + val logMessages = mutableListOf() + + fun clear() { + stringMessages.clear() + logMessages.clear() + } + } + } +} diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/integrationTest/kotlin/com/pubnub/api/integration/PNConfigurationIntegrationTests.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/integrationTest/kotlin/com/pubnub/api/integration/PNConfigurationIntegrationTests.kt index 7b1d56e874..624ebaf542 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/integrationTest/kotlin/com/pubnub/api/integration/PNConfigurationIntegrationTests.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/integrationTest/kotlin/com/pubnub/api/integration/PNConfigurationIntegrationTests.kt @@ -2,6 +2,8 @@ package com.pubnub.api.integration import com.pubnub.api.PubNub import com.pubnub.api.UserId +import com.pubnub.api.enums.PNLogVerbosity +import com.pubnub.api.integration.LoggingIntegrationTest.CustomLoggerTestImpl import com.pubnub.api.v2.PNConfiguration import com.pubnub.api.v2.PNConfigurationOverride import com.pubnub.test.CommonUtils.randomChannel @@ -34,6 +36,8 @@ class PNConfigurationIntegrationTests : BaseIntegrationTest() { val configBuilder = PNConfiguration.builder(UserId(expectedUuid), Keys.subKey) { publishKey = Keys.pubKey authToken = expectedAuthToken + logVerbosity = PNLogVerbosity.NONE + customLoggers = listOf(CustomLoggerTestImpl()) } val pubNub = PubNub.create(configBuilder.build()) diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/integrationTest/kotlin/com/pubnub/api/integration/PublishIntegrationTests.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/integrationTest/kotlin/com/pubnub/api/integration/PublishIntegrationTests.kt index 1f91e5afd2..0bbb45aedc 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/integrationTest/kotlin/com/pubnub/api/integration/PublishIntegrationTests.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/integrationTest/kotlin/com/pubnub/api/integration/PublishIntegrationTests.kt @@ -7,6 +7,7 @@ import com.pubnub.api.UserId import com.pubnub.api.callbacks.SubscribeCallback import com.pubnub.api.crypto.CryptoModule import com.pubnub.api.enums.PNStatusCategory +import com.pubnub.api.logging.LogConfig import com.pubnub.api.models.consumer.PNBoundedPage import com.pubnub.api.models.consumer.PNPublishResult import com.pubnub.api.models.consumer.PNStatus @@ -80,6 +81,7 @@ class PublishIntegrationTests : BaseIntegrationTest() { @Test fun testPublishMessageHistory() { + val logConfig = LogConfig("testPnInstanceId", "testUserId") val expectedChannel = randomChannel() val expectedPayload = @@ -88,7 +90,7 @@ class PublishIntegrationTests : BaseIntegrationTest() { addProperty("age", 48) } - val convertedPayload = MapperManager().convertValue(expectedPayload, JsonObject::class.java) + val convertedPayload = MapperManager(logConfig).convertValue(expectedPayload, JsonObject::class.java) pubnub.publish( channel = expectedChannel, diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/integrationTest/kotlin/com/pubnub/api/integration/PushIntegrationTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/integrationTest/kotlin/com/pubnub/api/integration/PushIntegrationTest.kt index db092e9aad..2f14c6a75b 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/integrationTest/kotlin/com/pubnub/api/integration/PushIntegrationTest.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/integrationTest/kotlin/com/pubnub/api/integration/PushIntegrationTest.kt @@ -39,10 +39,10 @@ class PushIntegrationTest : BaseIntegrationTest() { } private fun runPushOperations(pushType: PNPushType) { - logger.info("Push type '$pushType'") - logger.info("Channels $expectedChannels'") - logger.info("Topic $expectedTopic'") - logger.info("GeneratedToken '${expectedDeviceId.length}': $expectedDeviceId") + println("Push type '$pushType'") + println("Channels $expectedChannels'") + println("Topic $expectedTopic'") + println("GeneratedToken '${expectedDeviceId.length}': $expectedDeviceId") pubnub.addPushNotificationsOnChannels( channels = expectedChannels, diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/integrationTest/kotlin/com/pubnub/api/integration/pam/GrantTokenIntegrationTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/integrationTest/kotlin/com/pubnub/api/integration/pam/GrantTokenIntegrationTest.kt index 28e3c73351..eea0dba3a5 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/integrationTest/kotlin/com/pubnub/api/integration/pam/GrantTokenIntegrationTest.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/integrationTest/kotlin/com/pubnub/api/integration/pam/GrantTokenIntegrationTest.kt @@ -155,7 +155,6 @@ class GrantTokenIntegrationTest : BaseIntegrationTest() { subscribeKey = Keys.pamSubKey publishKey = Keys.pamPubKey logVerbosity = PNLogVerbosity.NONE - httpLoggingInterceptor = CommonUtils.createInterceptor(logger) } // setToken diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/EndpointCore.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/EndpointCore.kt index b0ff828613..aef7f8cda4 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/EndpointCore.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/EndpointCore.kt @@ -10,12 +10,13 @@ import com.pubnub.api.v2.PNConfiguration.Companion.isValid import com.pubnub.api.v2.PNConfigurationOverride import com.pubnub.api.v2.callbacks.Consumer import com.pubnub.api.v2.callbacks.Result +import com.pubnub.internal.logging.ConfigurationLogger.logConfiguration +import com.pubnub.internal.logging.LoggerManager import com.pubnub.internal.managers.RetrofitManager import com.pubnub.internal.retry.RetryableBase import com.pubnub.internal.retry.RetryableCallback import com.pubnub.internal.retry.RetryableRestCaller import com.pubnub.internal.v2.PNConfigurationImpl -import org.slf4j.LoggerFactory import retrofit2.Call import retrofit2.Response import java.io.IOException @@ -40,7 +41,7 @@ abstract class EndpointCore protected constructor(protected val p RetrofitManager(pubnub.retrofitManager, configOverrideNonNull) } ?: pubnub.retrofitManager - private val log = LoggerFactory.getLogger(this.javaClass.simpleName) + private val logger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) private lateinit var cachedCallback: Consumer> private lateinit var call: Call @@ -50,6 +51,7 @@ abstract class EndpointCore protected constructor(protected val p configuration.retryConfiguration, getEndpointGroupName(), isEndpointRetryable(), + pubnub.logConfig ) } @@ -119,6 +121,7 @@ abstract class EndpointCore protected constructor(protected val p endpointGroupName = getEndpointGroupName(), isEndpointRetryable = isEndpointRetryable(), executorService = pubnub.executorService, + logConfig = pubnub.logConfig ) { override fun onFinalResponse( call: Call, @@ -439,6 +442,7 @@ abstract class EndpointCore protected constructor(protected val p } fun overrideConfigurationInternal(configuration: PNConfiguration) { + logConfiguration(configuration = configuration, logger = logger, instanceId = pubnub.instanceId, className = this::class.java) this.configOverride = configuration } diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/PubNubImpl.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/PubNubImpl.kt index e9aecc6d1b..0b5e8cafa4 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/PubNubImpl.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/PubNubImpl.kt @@ -52,6 +52,10 @@ import com.pubnub.api.endpoints.push.RemoveAllPushChannelsForDevice import com.pubnub.api.endpoints.push.RemoveChannelsFromPush import com.pubnub.api.enums.PNPushEnvironment import com.pubnub.api.enums.PNPushType +import com.pubnub.api.logging.ErrorDetails +import com.pubnub.api.logging.LogConfig +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.PNBoundedPage import com.pubnub.api.models.consumer.access_manager.sum.SpacePermissions import com.pubnub.api.models.consumer.access_manager.sum.UserPermissions @@ -89,6 +93,7 @@ import com.pubnub.api.v2.subscriptions.Subscription import com.pubnub.api.v2.subscriptions.SubscriptionCursor import com.pubnub.api.v2.subscriptions.SubscriptionOptions import com.pubnub.api.v2.subscriptions.SubscriptionSet +import com.pubnub.internal.crypto.CryptoModuleImpl import com.pubnub.internal.crypto.decryptString import com.pubnub.internal.crypto.encryptString import com.pubnub.internal.endpoints.DeleteMessagesEndpoint @@ -139,6 +144,9 @@ import com.pubnub.internal.endpoints.push.AddChannelsToPushEndpoint import com.pubnub.internal.endpoints.push.ListPushProvisionsEndpoint import com.pubnub.internal.endpoints.push.RemoveAllPushChannelsForDeviceEndpoint import com.pubnub.internal.endpoints.push.RemoveChannelsFromPushEndpoint +import com.pubnub.internal.logging.ConfigurationLogger.logConfiguration +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.managers.BasePathManager import com.pubnub.internal.managers.DuplicationManager import com.pubnub.internal.managers.ListenerManager @@ -154,6 +162,7 @@ import com.pubnub.internal.presence.eventengine.effect.effectprovider.LeaveProvi import com.pubnub.internal.subscribe.PRESENCE_CHANNEL_SUFFIX import com.pubnub.internal.subscribe.Subscribe import com.pubnub.internal.subscribe.eventengine.configuration.EventEnginesConf +import com.pubnub.internal.v2.PNConfigurationImpl import com.pubnub.internal.v2.entities.ChannelGroupImpl import com.pubnub.internal.v2.entities.ChannelGroupName import com.pubnub.internal.v2.entities.ChannelImpl @@ -180,20 +189,34 @@ open class PubNubImpl( val pnsdkName: String = PNSDK_PUBNUB_KOTLIN, eventEnginesConf: EventEnginesConf = EventEnginesConf() ) : PubNub { + protected val logger: PNLogger by lazy { LoggerManager.instance.getLogger(logConfig, this::class.java) } internal val tokenManager: TokenManager = TokenManager() init { this.setToken(configuration.authToken) } + constructor(configuration: PNConfiguration) : this(configuration, PNSDK_PUBNUB_KOTLIN) - val mapper = MapperManager() + /** + * Unique id of this PubNub instance. + * + * @see [PNConfiguration.includeInstanceIdentifier] + */ + val instanceId = UUID.randomUUID().toString() + val logConfig: LogConfig = LogConfig( + pnInstanceId = instanceId, + userId = configuration.userId.value, + customLoggers = configuration.customLoggers, + ) + + val mapper = MapperManager(logConfig) private val numberOfThreadsInPool = Integer.min(Runtime.getRuntime().availableProcessors(), 8) internal val executorService: ScheduledExecutorService = Executors.newScheduledThreadPool(numberOfThreadsInPool) val listenerManager: ListenerManager = ListenerManager(this) private val basePathManager = BasePathManager(configuration) - internal val retrofitManager = RetrofitManager(this, configuration) + internal val retrofitManager = RetrofitManager(pubnub = this, configuration = configuration) internal val publishSequenceManager = PublishSequenceManager(MAX_SEQUENCE) private val tokenParser: TokenParser = TokenParser() private val presenceData = PresenceData() @@ -202,7 +225,7 @@ open class PubNubImpl( this, listenerManager, eventEnginesConf, - SubscribeMessageProcessor(this, DuplicationManager(configuration)), + SubscribeMessageProcessor(this, DuplicationManager(configuration), logConfig), presenceData, configuration.maintainPresenceState, ) @@ -219,14 +242,34 @@ open class PubNubImpl( presenceData = presenceData, sendStateWithHeartbeat = configuration.maintainPresenceState, executorService = executorService, + logConfig = logConfig, ) - /** - * Unique id of this PubNub instance. - * - * @see [PNConfiguration.includeInstanceIdentifier] - */ - val instanceId = UUID.randomUUID().toString() + internal val cryptoModuleWithLogConfig: CryptoModule? by lazy { + when (configuration) { + is PNConfigurationImpl -> (configuration as PNConfigurationImpl).getCryptoModuleWithLogConfig(logConfig) + else -> { + // Try to call getCryptoModuleWithLogConfig using reflection for Java implementation + try { + val method = configuration.javaClass.getMethod("getCryptoModuleWithLogConfig", LogConfig::class.java) + method.invoke(configuration, logConfig) as? CryptoModule + } catch (e: Exception) { + logger.error( + LogMessage( + message = LogMessageContent.Error( + message = ErrorDetails( + type = e.javaClass.simpleName, + message = "Failed calling getCryptoModuleWithLogConfig" + ) + ), + details = "details", + ) + ) + null + } + } + } + } //region Internal internal fun baseUrl() = basePathManager.basePath() @@ -276,6 +319,15 @@ open class PubNubImpl( fun generateUUID() = "pn-${UUID.randomUUID()}" } + init { + logConfiguration( + configuration = configuration, + logger = logger, + instanceId = instanceId, + className = this::class.java + ) + } + override fun subscriptionSetOf( channels: Set, channelGroups: Set, @@ -372,7 +424,17 @@ open class PubNubImpl( meta: Any?, usePost: Boolean, ttl: Int?, - ): Publish = fire(channel, message, meta, usePost) + ): Publish { + logger.warn( + LogMessage( + message = LogMessageContent.Text( + "DEPRECATED: fire() with ttl parameter is deprecated. Use fire(channel, message, meta, usePost) instead." + ), + details = "The ttl parameter is not used and this method will be removed in a future version", + ) + ) + return fire(channel, message, meta, usePost) + } override fun signal( channel: String, @@ -453,6 +515,14 @@ open class PubNubImpl( includeTimetoken: Boolean, includeMeta: Boolean, ): History { + logger.warn( + LogMessage( + message = LogMessageContent.Text( + "DEPRECATED: history() is deprecated. Use fetchMessages() instead." + ), + details = "This method will be removed in a future version", + ) + ) return HistoryEndpoint( pubnub = this, channel = channel, @@ -1450,6 +1520,7 @@ open class PubNubImpl( includeUserType = includeUUIDType, ) } + PNUUIDDetailsLevel.UUID_WITH_CUSTOM -> { IncludeQueryParam( includeCustom = includeCustom, @@ -1458,6 +1529,7 @@ open class PubNubImpl( includeUserType = includeUUIDType, ) } + null -> IncludeQueryParam(includeCustom = includeCustom, includeUserType = includeUUIDType) } return ManageChannelMembersEndpoint( @@ -1523,9 +1595,9 @@ open class PubNubImpl( ): SendFile { val cryptoModule = if (cipherKey != null) { - CryptoModule.createLegacyCryptoModule(cipherKey) + createCryptoModuleWithLogConfig(CryptoModule.createLegacyCryptoModule(cipherKey)) } else { - configuration.cryptoModule + cryptoModuleWithLogConfig } return SendFileEndpoint( channel = channel, @@ -1581,9 +1653,9 @@ open class PubNubImpl( ): DownloadFile { val cryptoModule = if (cipherKey != null) { - CryptoModule.createLegacyCryptoModule(cipherKey) + createCryptoModuleWithLogConfig(CryptoModule.createLegacyCryptoModule(cipherKey)) } else { - configuration.cryptoModule + cryptoModuleWithLogConfig } return DownloadFileEndpoint( pubNub = this, @@ -1645,8 +1717,10 @@ open class PubNubImpl( ) private fun getCryptoModuleOrThrow(cipherKey: String? = null): CryptoModule { - return cipherKey?.let { cipherKeyNotNull -> CryptoModule.createLegacyCryptoModule(cipherKeyNotNull) } - ?: configuration.cryptoModule ?: throw PubNubException("Crypto module is not initialized") + return cipherKey?.let { cipherKeyNotNull -> + createCryptoModuleWithLogConfig(CryptoModule.createLegacyCryptoModule(cipherKeyNotNull)) + } + ?: cryptoModuleWithLogConfig ?: throw PubNubException("Crypto module is not initialized") } @Throws(PubNubException::class) @@ -1965,6 +2039,20 @@ open class PubNubImpl( @Throws(PubNubException::class) private fun getCryptoModuleOrThrow(cryptoModule: CryptoModule? = null): CryptoModule { - return cryptoModule ?: configuration.cryptoModule ?: throw PubNubException("Crypto module is not initialized") + return cryptoModule?.let { createCryptoModuleWithLogConfig(it) } ?: cryptoModuleWithLogConfig + ?: throw PubNubException("Crypto module is not initialized") + } + + private fun createCryptoModuleWithLogConfig(cryptoModule: CryptoModule): CryptoModule { + return if (cryptoModule is CryptoModuleImpl) { + CryptoModuleImpl( + primaryCryptor = cryptoModule.primaryCryptor, + cryptorsForDecryptionOnly = cryptoModule.cryptorsForDecryptionOnly, + logConfig = logConfig + ) + } else { + // For custom implementations, return the original instance + cryptoModule + } } } diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/PubNubUtil.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/PubNubUtil.kt index cf128d2bcd..b0a1f3ce1a 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/PubNubUtil.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/PubNubUtil.kt @@ -5,7 +5,6 @@ import com.pubnub.api.v2.PNConfiguration import com.pubnub.api.v2.PNConfiguration.Companion.isValid import okhttp3.Request import okio.Buffer -import org.slf4j.LoggerFactory import java.io.IOException import java.io.UnsupportedEncodingException import java.net.URLDecoder @@ -19,8 +18,6 @@ import javax.crypto.Mac import javax.crypto.spec.SecretKeySpec internal object PubNubUtil { - private val log = LoggerFactory.getLogger("PubNubUtil") - private const val CHARSET = "UTF-8" const val SIGNATURE_QUERY_PARAM_NAME = "signature" const val TIMESTAMP_QUERY_PARAM_NAME = "timestamp" @@ -128,9 +125,9 @@ internal object PubNubUtil { signature = "v2.$signature" } } catch (e: PubNubException) { - log.warn("signature failed on SignatureInterceptor: $e") + // do nothing } catch (e: UnsupportedEncodingException) { - log.warn("signature failed on SignatureInterceptor: $e") + // do nothing } return signature } diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/crypto/CryptoModuleImpl.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/crypto/CryptoModuleImpl.kt index 04390fd15e..58e37758b7 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/crypto/CryptoModuleImpl.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/crypto/CryptoModuleImpl.kt @@ -6,56 +6,84 @@ import com.pubnub.api.crypto.CryptoModule import com.pubnub.api.crypto.cryptor.Cryptor import com.pubnub.api.crypto.data.EncryptedData import com.pubnub.api.crypto.data.EncryptedStreamData +import com.pubnub.api.logging.LogConfig +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.internal.crypto.cryptor.HeaderParser import com.pubnub.internal.crypto.cryptor.LEGACY_CRYPTOR_ID import com.pubnub.internal.crypto.cryptor.ParseResult +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import java.io.BufferedInputStream import java.io.InputStream import java.io.SequenceInputStream private const val SIZE_OF_CRYPTOR_ID = 4 -class CryptoModuleImpl internal constructor( +/** + * Public constructor for internal cross-module access only. + * This class is in an internal package and should not be used directly by consumers. + * Use CryptoModule factory methods instead. + */ +class CryptoModuleImpl( @get:JvmSynthetic - internal val primaryCryptor: Cryptor, + val primaryCryptor: Cryptor, @get:JvmSynthetic - internal val cryptorsForDecryptionOnly: List = listOf(), + val cryptorsForDecryptionOnly: List = listOf(), + @get:JvmSynthetic + val logConfig: LogConfig? = null, ) : CryptoModule { - private val headerParser: HeaderParser = HeaderParser() + private val log: PNLogger by lazy { + logConfig?.let { LoggerManager.instance.getLogger(it, this::class.java) } + ?: LoggerManager.instance.getLogger(LogConfig("default", "default"), this::class.java) + } + + private val headerParser: HeaderParser = HeaderParser(logConfig) override fun encrypt(data: ByteArray): ByteArray { + logDebugMessage("Encrypting data of size: ${data.size} bytes") + val cryptorId = primaryCryptor.id() validateData(data) validateCryptorIdSize(cryptorId) val (metadata, encryptedData) = primaryCryptor.encrypt(data) - return if (cryptorId.contentEquals(LEGACY_CRYPTOR_ID)) { + val result = if (cryptorId.contentEquals(LEGACY_CRYPTOR_ID)) { encryptedData } else { val cryptorHeader = headerParser.createCryptorHeader(cryptorId, metadata) cryptorHeader + encryptedData } + logDebugMessage("Encrypting successful") + return result } override fun decrypt(encryptedData: ByteArray): ByteArray { + logDebugMessage("Decrypting data of size: ${encryptedData.size} bytes") + validateData(encryptedData) val parsedData: ParseResult = headerParser.parseDataWithHeader(encryptedData) val decryptedData: ByteArray = when (parsedData) { is ParseResult.NoHeader -> { + logDebugMessage("Using legacy cryptor for decryption") getDecryptedDataForLegacyCryptor(encryptedData) } is ParseResult.Success -> { + logDebugMessage("Using cryptor with header for decryption") getDecryptedDataForCryptorWithHeader(parsedData) } } + logDebugMessage("Decryption successful") return decryptedData } override fun encryptStream(stream: InputStream): InputStream { + logDebugMessage("Encrypting stream") val bufferedInputStream = validateStreamAndReturnBuffered(stream) val (metadata, encryptedData) = primaryCryptor.encryptStream(bufferedInputStream) + logDebugMessage("Encrypting stream successful") return if (primaryCryptor.id().contentEquals(LEGACY_CRYPTOR_ID)) { encryptedData } else { @@ -65,6 +93,7 @@ class CryptoModuleImpl internal constructor( } override fun decryptStream(encryptedData: InputStream): InputStream { + logDebugMessage("Decrypting stream") val bufferedInputStream = validateStreamAndReturnBuffered(encryptedData) return when (val parsedHeader = headerParser.parseDataWithHeader(bufferedInputStream)) { ParseResult.NoHeader -> { @@ -90,6 +119,10 @@ class CryptoModuleImpl internal constructor( } } + private fun logDebugMessage(message: String) { + log.debug(LogMessage(message = LogMessageContent.Text(message))) + } + private fun validateCryptorIdSize(cryptorId: ByteArray) { if (cryptorId.size != SIZE_OF_CRYPTOR_ID) { throw PubNubException( diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/crypto/cryptor/HeaderParser.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/crypto/cryptor/HeaderParser.kt index 032c59c3ba..d0610e8b74 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/crypto/cryptor/HeaderParser.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/crypto/cryptor/HeaderParser.kt @@ -2,8 +2,11 @@ package com.pubnub.internal.crypto.cryptor import com.pubnub.api.PubNubError import com.pubnub.api.PubNubException +import com.pubnub.api.logging.LogConfig +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.internal.crypto.readExactlyNBytez -import org.slf4j.LoggerFactory +import com.pubnub.internal.logging.LoggerManager import java.io.BufferedInputStream import java.io.InputStream @@ -24,8 +27,13 @@ private const val THREE_BYTES_CRYPTOR_DATA_SIZE_ENDING_INDEX = 11 private const val MAX_VALUE_THAT_CAN_BE_STORED_ON_TWO_BYTES = 65535 private const val MINIMAL_SIZE_OF_CRYPTO_HEADER = 10 -internal class HeaderParser { - private val log = LoggerFactory.getLogger(HeaderParser::class.java) +internal class HeaderParser(val logConfig: LogConfig?) { + private val log = logConfig?.let { + LoggerManager.instance.getLogger(logConfig = it, clazz = this::class.java) + } ?: LoggerManager.instance.getLogger( + logConfig = LogConfig("default", "default"), + clazz = this::class.java + ) fun parseDataWithHeader(stream: BufferedInputStream): ParseResult { val bufferedInputStream = stream.buffered() @@ -81,8 +89,7 @@ internal class HeaderParser { if (data.size < MINIMAL_SIZE_OF_DATA_HAVING_CRYPTOR_HEADER) { throw PubNubException( - errorMessage = - "Minimal size of encrypted data having Cryptor Data Header is: $MINIMAL_SIZE_OF_DATA_HAVING_CRYPTOR_HEADER", + errorMessage = "Minimal size of encrypted data having Cryptor Data Header is: $MINIMAL_SIZE_OF_DATA_HAVING_CRYPTOR_HEADER", pubnubError = PubNubError.CRYPTOR_DATA_HEADER_SIZE_TO_SMALL, ) } @@ -90,7 +97,7 @@ internal class HeaderParser { validateCryptorHeaderVersion(data) val cryptorId = data.sliceArray(CRYPTOR_ID_STARTING_INDEX..CRYPTOR_ID_ENDING_INDEX) - log.trace("CryptoId: ${String(cryptorId, Charsets.UTF_8)}") + logTraceMessage("CryptoId: ${String(cryptorId, Charsets.UTF_8)}") val cryptorDataSizeFirstByte: Byte = data[CRYPTOR_DATA_SIZE_STARTING_INDEX] val (startingIndexOfCryptorData, cryptorDataSize) = @@ -128,9 +135,7 @@ internal class HeaderParser { byteArrayOf(cryptorDataSize.toByte()) + writeNumberOnTwoBytes(cryptorDataSize) } else { throw PubNubException( - errorMessage = - "Cryptor Data Size is: $cryptorDataSize whereas " + - "max cryptor data size is: $MAX_VALUE_THAT_CAN_BE_STORED_ON_TWO_BYTES", + errorMessage = "Cryptor Data Size is: $cryptorDataSize whereas max cryptor data size is: $MAX_VALUE_THAT_CAN_BE_STORED_ON_TWO_BYTES", pubnubError = PubNubError.CRYPTOR_HEADER_PARSE_ERROR, ) } @@ -154,14 +159,14 @@ internal class HeaderParser { if (cryptoDataFirstByteAsUByte == THREE_BYTES_SIZE_CRYPTOR_DATA_INDICATOR) { startingIndexOfCryptorData = STARTING_INDEX_OF_THREE_BYTES_CRYPTOR_DATA_SIZE - log.trace("\"Cryptor data size\" first byte's value is 255 that mean that size is stored on two next bytes") + logTraceMessage("\"Cryptor data size\" first byte's value is 255 that mean that size is stored on two next bytes") val cryptorDataSizeSecondByte = data[THREE_BYTES_CRYPTOR_DATA_SIZE_STARTING_INDEX] val cryptorDataSizeThirdByte = data[THREE_BYTES_CRYPTOR_DATA_SIZE_ENDING_INDEX] cryptorDataSize = convertTwoBytesToIntBigEndian(cryptorDataSizeSecondByte, cryptorDataSizeThirdByte) } else { startingIndexOfCryptorData = STARTING_INDEX_OF_ONE_BYTE_CRYPTOR_DATA_SIZE cryptorDataSize = cryptoDataFirstByteAsUByte.toInt() - log.trace("\"Cryptor data size\" is 1 byte long and its value is: $cryptorDataSize") + logTraceMessage("\"Cryptor data size\" is 1 byte long and its value is: $cryptorDataSize") } return Pair(startingIndexOfCryptorData, cryptorDataSize) } @@ -169,7 +174,7 @@ internal class HeaderParser { private fun validateCryptorHeaderVersion(data: ByteArray) { val version: UByte = data[VERSION_INDEX].toUByte() // 5th byte val versionAsInt = version.toInt() - log.trace("Cryptor header version is: $versionAsInt") + logTraceMessage("Cryptor header version is: $versionAsInt") // check if version exist in this SDK version CryptorHeaderVersion.fromValue(versionAsInt) ?: throw PubNubException( @@ -178,6 +183,10 @@ internal class HeaderParser { ) } + private fun logTraceMessage(message: String) { + log.trace(LogMessage(message = LogMessageContent.Text(message))) + } + private fun convertTwoBytesToIntBigEndian( byte1: Byte, byte2: Byte, diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/DeleteMessagesEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/DeleteMessagesEndpoint.kt index b9132d07d6..afde56ef4b 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/DeleteMessagesEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/DeleteMessagesEndpoint.kt @@ -4,10 +4,14 @@ import com.pubnub.api.PubNubError import com.pubnub.api.PubNubException import com.pubnub.api.endpoints.DeleteMessages import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.history.PNDeleteMessagesResult import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.toCsv import retrofit2.Call import retrofit2.Response @@ -22,6 +26,8 @@ class DeleteMessagesEndpoint internal constructor( override val start: Long? = null, override val end: Long? = null, ) : EndpointCore(pubnub), DeleteMessages { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun validateParams() { super.validateParams() if (channels.isEmpty()) { @@ -30,6 +36,20 @@ class DeleteMessagesEndpoint internal constructor( } override fun doWork(queryParams: HashMap): Call { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "channels" to channels, + "start" to (start ?: ""), + "end" to (end ?: ""), + "queryParams" to queryParams + ) + ), + details = "DeleteMessages API call", + ) + ) + addQueryParams(queryParams) return retrofitManager.historyService.deleteMessages( diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/FetchMessagesEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/FetchMessagesEndpoint.kt index 46bd3d4342..c884441ba9 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/FetchMessagesEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/FetchMessagesEndpoint.kt @@ -4,6 +4,8 @@ import com.pubnub.api.PubNubError import com.pubnub.api.PubNubException import com.pubnub.api.endpoints.FetchMessages import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.PNBoundedPage import com.pubnub.api.models.consumer.history.HistoryMessageType import com.pubnub.api.models.consumer.history.PNFetchMessageItem @@ -14,6 +16,8 @@ import com.pubnub.internal.PubNubImpl import com.pubnub.internal.extension.limit import com.pubnub.internal.extension.nonPositiveToNull import com.pubnub.internal.extension.tryDecryptMessage +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.models.server.FetchMessagesEnvelope import com.pubnub.internal.models.server.history.ServerFetchMessageItem import com.pubnub.internal.toCsv @@ -34,6 +38,8 @@ class FetchMessagesEndpoint internal constructor( override val includeMessageType: Boolean = false, override val includeCustomMessageType: Boolean = false ) : EndpointCore(pubnub), FetchMessages { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + internal companion object { private const val SINGLE_CHANNEL_DEFAULT_MESSAGES = 100 private const val SINGLE_CHANNEL_MAX_MESSAGES = 100 @@ -77,6 +83,24 @@ class FetchMessagesEndpoint internal constructor( override fun getAffectedChannels() = channels override fun doWork(queryParams: HashMap): Call { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "channels" to channels, + "page" to page, + "includeUUID" to includeUUID, + "includeMeta" to includeMeta, + "includeMessageActions" to includeMessageActions, + "includeMessageType" to includeMessageType, + "includeCustomMessageType" to includeCustomMessageType, + "queryParams" to queryParams + ) + ), + details = "FetchMessages API call", + ) + ) + addQueryParams(queryParams) return if (!includeMessageActions) { @@ -101,8 +125,9 @@ class FetchMessagesEndpoint internal constructor( value.map { serverMessageItem: ServerFetchMessageItem -> val (newMessage, error) = serverMessageItem.message.tryDecryptMessage( - configuration.cryptoModule, + pubnub.cryptoModuleWithLogConfig, pubnub.mapper, + log, ) val newActions = if (includeMessageActions) { diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/HistoryEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/HistoryEndpoint.kt index c869a37608..b9ce161006 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/HistoryEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/HistoryEndpoint.kt @@ -5,12 +5,16 @@ import com.pubnub.api.PubNubError import com.pubnub.api.PubNubException import com.pubnub.api.endpoints.History import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.history.PNHistoryItemResult import com.pubnub.api.models.consumer.history.PNHistoryResult import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl import com.pubnub.internal.extension.tryDecryptMessage +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import retrofit2.Call import retrofit2.Response import java.util.Locale @@ -28,6 +32,7 @@ class HistoryEndpoint internal constructor( override val includeTimetoken: Boolean, override val includeMeta: Boolean, ) : EndpointCore(pubnub), History { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) private val countParam: Int = if (count in 1..PNHistoryResult.MAX_COUNT) { count @@ -45,6 +50,24 @@ class HistoryEndpoint internal constructor( override fun getAffectedChannels() = listOf(channel) override fun doWork(queryParams: HashMap): Call { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "channel" to channel, + "start" to (start ?: ""), + "end" to (end ?: ""), + "count" to count, + "reverse" to reverse, + "includeTimetoken" to includeTimetoken, + "includeMeta" to includeMeta, + "queryParams" to queryParams + ) + ), + details = "History API call", + ) + ) + addQueryParams(queryParams) return retrofitManager.historyService.fetchHistory( @@ -81,7 +104,7 @@ class HistoryEndpoint internal constructor( if (includeTimetoken || includeMeta) { historyMessageWithError = pubnub.mapper.getField(historyEntry, "message")!! - .tryDecryptMessage(configuration.cryptoModule, pubnub.mapper) + .tryDecryptMessage(pubnub.cryptoModuleWithLogConfig, pubnub.mapper, log) if (includeTimetoken) { timetoken = pubnub.mapper.elementToLong(historyEntry, "timetoken") } @@ -89,7 +112,11 @@ class HistoryEndpoint internal constructor( meta = pubnub.mapper.getField(historyEntry, "meta") } } else { - historyMessageWithError = historyEntry.tryDecryptMessage(configuration.cryptoModule, pubnub.mapper) + historyMessageWithError = historyEntry.tryDecryptMessage( + pubnub.cryptoModuleWithLogConfig, + pubnub.mapper, + log, + ) } val message: JsonElement = historyMessageWithError.first diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/MessageCountsEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/MessageCountsEndpoint.kt index ab8a7b8e09..4654ea4f23 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/MessageCountsEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/MessageCountsEndpoint.kt @@ -5,10 +5,14 @@ import com.pubnub.api.PubNubError import com.pubnub.api.PubNubException import com.pubnub.api.endpoints.MessageCounts import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.history.PNMessageCountResult import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.toCsv import retrofit2.Call import retrofit2.Response @@ -21,6 +25,8 @@ class MessageCountsEndpoint internal constructor( override val channels: List, override val channelsTimetoken: List, ) : EndpointCore(pubnub), MessageCounts { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun validateParams() { super.validateParams() if (channels.isEmpty()) { @@ -37,6 +43,19 @@ class MessageCountsEndpoint internal constructor( override fun getAffectedChannels() = channels override fun doWork(queryParams: HashMap): Call { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "channels" to channels, + "channelsTimetoken" to channelsTimetoken, + "queryParams" to queryParams + ) + ), + details = "MessageCounts API call", + ) + ) + addQueryParams(queryParams) return retrofitManager.historyService.fetchCount( diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/TimeEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/TimeEndpoint.kt index edfee085cf..567042dcee 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/TimeEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/TimeEndpoint.kt @@ -2,10 +2,15 @@ package com.pubnub.internal.endpoints import com.pubnub.api.endpoints.Time import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.PNTimeResult import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger +import retrofit2.Call import retrofit2.Response /** @@ -14,11 +19,27 @@ import retrofit2.Response class TimeEndpoint(pubnub: PubNubImpl, private val excludeFromRetry: Boolean = false) : EndpointCore, PNTimeResult>(pubnub), Time { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun getAffectedChannels() = emptyList() override fun getAffectedChannelGroups() = emptyList() - override fun doWork(queryParams: HashMap) = retrofitManager.timeService.fetchTime(queryParams) + override fun doWork(queryParams: HashMap): Call> { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "excludeFromRetry" to excludeFromRetry, + "queryParams" to queryParams + ) + ), + details = "Time API call", + ) + ) + + return retrofitManager.timeService.fetchTime(queryParams) + } override fun createResponse(input: Response>): PNTimeResult { return PNTimeResult(input.body()!![0]) diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/access/GrantEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/access/GrantEndpoint.kt index 8210e8451b..ddcae74f48 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/access/GrantEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/access/GrantEndpoint.kt @@ -5,12 +5,16 @@ import com.pubnub.api.PubNubError import com.pubnub.api.PubNubException import com.pubnub.api.endpoints.access.Grant import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.access_manager.PNAccessManagerGrantResult import com.pubnub.api.models.consumer.access_manager.PNAccessManagerKeyData import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.api.v2.PNConfiguration.Companion.isValid import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.models.server.Envelope import com.pubnub.internal.models.server.access_manager.AccessManagerGrantPayload import com.pubnub.internal.toCsv @@ -35,6 +39,8 @@ open class GrantEndpoint( override val channelGroups: List = emptyList(), override val uuids: List = emptyList(), ) : EndpointCore, PNAccessManagerGrantResult>(pubnub), Grant { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun validateParams() { super.validateParams() if (!pubnub.configuration.secretKey.isValid()) { @@ -47,6 +53,29 @@ open class GrantEndpoint( override fun getAffectedChannelGroups() = channelGroups override fun doWork(queryParams: HashMap): Call> { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "read" to read, + "write" to write, + "manage" to manage, + "delete" to delete, + "get" to get, + "update" to update, + "join" to join, + "ttl" to ttl, + "authKeys" to authKeys, + "channels" to channels, + "channelGroups" to channelGroups, + "uuids" to uuids, + "queryParams" to queryParams + ) + ), + details = "Grant API call", + ) + ) + addQueryParams(queryParams) return retrofitManager.accessManagerService diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/access/GrantTokenEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/access/GrantTokenEndpoint.kt index 19dc000e72..8fb9d4018b 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/access/GrantTokenEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/access/GrantTokenEndpoint.kt @@ -4,6 +4,8 @@ import com.pubnub.api.PubNubError import com.pubnub.api.PubNubException import com.pubnub.api.endpoints.access.GrantToken import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.access_manager.v3.ChannelGrant import com.pubnub.api.models.consumer.access_manager.v3.ChannelGroupGrant import com.pubnub.api.models.consumer.access_manager.v3.PNGrantTokenResult @@ -12,6 +14,8 @@ import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.api.v2.PNConfiguration.Companion.isValid import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.models.server.access_manager.v3.GrantTokenRequestBody import com.pubnub.internal.models.server.access_manager.v3.GrantTokenResponse import retrofit2.Call @@ -26,6 +30,8 @@ class GrantTokenEndpoint( private val channelGroups: List, private val uuids: List, ) : EndpointCore(pubnub), GrantToken { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun getAffectedChannels(): List = channels.map { it.id } override fun getAffectedChannelGroups(): List = channelGroups.map { it.id } @@ -46,6 +52,25 @@ class GrantTokenEndpoint( } override fun doWork(queryParams: HashMap): Call { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "ttl" to ttl, + "meta" to (meta ?: ""), + "authorizedUUID" to (authorizedUUID ?: ""), + "channels" to channels.map { + mapOf("id" to it.id, "read" to it.read, "write" to it.write, "manage" to it.manage, "delete" to it.delete, "get" to it.get, "update" to it.update, "join" to it.join) + }, + "channelGroups" to channelGroups.map { mapOf("id" to it.id, "read" to it.read, "write" to it.write, "manage" to it.manage) }, + "uuids" to uuids.map { mapOf("id" to it.id, "get" to it.get, "update" to it.update, "delete" to it.delete) }, + "queryParams" to queryParams + ) + ), + details = "GrantToken API call", + ) + ) + val requestBody: GrantTokenRequestBody = GrantTokenRequestBody.of( ttl = ttl, diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/access/RevokeTokenEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/access/RevokeTokenEndpoint.kt index 789e8f0175..9bf0f1cbc1 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/access/RevokeTokenEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/access/RevokeTokenEndpoint.kt @@ -4,10 +4,14 @@ import com.pubnub.api.PubNubError import com.pubnub.api.PubNubException import com.pubnub.api.endpoints.access.RevokeToken import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.api.v2.PNConfiguration.Companion.isValid import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.models.server.access_manager.v3.RevokeTokenResponse import retrofit2.Call import retrofit2.Response @@ -17,6 +21,8 @@ class RevokeTokenEndpoint( pubnub: PubNubImpl, private val token: String, ) : EndpointCore(pubnub), RevokeToken { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun validateParams() { super.validateParams() if (!pubnub.configuration.secretKey.isValid()) { @@ -28,6 +34,18 @@ class RevokeTokenEndpoint( } override fun doWork(queryParams: HashMap): Call { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "token" to token, + "queryParams" to queryParams + ) + ), + details = "RevokeToken API call", + ) + ) + return retrofitManager .accessManagerService .revokeToken(configuration.subscribeKey, repairEncoding(token), queryParams) diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/channel_groups/AddChannelChannelGroupEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/channel_groups/AddChannelChannelGroupEndpoint.kt index 18550b48de..81142a359d 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/channel_groups/AddChannelChannelGroupEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/channel_groups/AddChannelChannelGroupEndpoint.kt @@ -4,10 +4,14 @@ import com.pubnub.api.PubNubError import com.pubnub.api.PubNubException import com.pubnub.api.endpoints.channel_groups.AddChannelChannelGroup import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.channel_group.PNChannelGroupsAddChannelResult import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.toCsv import retrofit2.Call import retrofit2.Response @@ -20,6 +24,8 @@ class AddChannelChannelGroupEndpoint internal constructor( override val channelGroup: String, override val channels: List, ) : EndpointCore(pubnub), AddChannelChannelGroup { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun getAffectedChannels() = channels override fun getAffectedChannelGroups() = listOf(channelGroup) @@ -35,6 +41,19 @@ class AddChannelChannelGroupEndpoint internal constructor( } override fun doWork(queryParams: HashMap): Call { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "channelGroup" to channelGroup, + "channels" to channels, + "queryParams" to queryParams + ) + ), + details = "AddChannelChannelGroup API call", + ) + ) + addQueryParams(queryParams) return retrofitManager.channelGroupService diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/channel_groups/AllChannelsChannelGroupEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/channel_groups/AllChannelsChannelGroupEndpoint.kt index 7c6c074cfb..eba83bb319 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/channel_groups/AllChannelsChannelGroupEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/channel_groups/AllChannelsChannelGroupEndpoint.kt @@ -4,10 +4,14 @@ import com.pubnub.api.PubNubError import com.pubnub.api.PubNubException import com.pubnub.api.endpoints.channel_groups.AllChannelsChannelGroup import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.channel_group.PNChannelGroupsAllChannelsResult import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.models.server.Envelope import retrofit2.Call import retrofit2.Response @@ -20,6 +24,8 @@ class AllChannelsChannelGroupEndpoint internal constructor( override val channelGroup: String, ) : EndpointCore>, PNChannelGroupsAllChannelsResult>(pubnub), AllChannelsChannelGroup { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun getAffectedChannelGroups() = listOf(channelGroup) override fun validateParams() { @@ -30,6 +36,18 @@ class AllChannelsChannelGroupEndpoint internal constructor( } override fun doWork(queryParams: HashMap): Call>> { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "channelGroup" to channelGroup, + "queryParams" to queryParams + ) + ), + details = "AllChannelsChannelGroup API call", + ) + ) + return retrofitManager.channelGroupService .allChannelsChannelGroup( configuration.subscribeKey, diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/channel_groups/DeleteChannelGroupEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/channel_groups/DeleteChannelGroupEndpoint.kt index f06ba172d4..d6a79fff8f 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/channel_groups/DeleteChannelGroupEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/channel_groups/DeleteChannelGroupEndpoint.kt @@ -4,10 +4,14 @@ import com.pubnub.api.PubNubError import com.pubnub.api.PubNubException import com.pubnub.api.endpoints.channel_groups.DeleteChannelGroup import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.channel_group.PNChannelGroupsDeleteGroupResult import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import retrofit2.Call import retrofit2.Response @@ -18,6 +22,8 @@ class DeleteChannelGroupEndpoint internal constructor( pubnub: PubNubImpl, override val channelGroup: String, ) : EndpointCore(pubnub), DeleteChannelGroup { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun validateParams() { super.validateParams() if (channelGroup.isBlank()) { @@ -28,6 +34,18 @@ class DeleteChannelGroupEndpoint internal constructor( override fun getAffectedChannelGroups() = listOf(channelGroup) override fun doWork(queryParams: HashMap): Call { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "channelGroup" to channelGroup, + "queryParams" to queryParams + ) + ), + details = "DeleteChannelGroup API call", + ) + ) + return retrofitManager.channelGroupService .deleteChannelGroup( configuration.subscribeKey, diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/channel_groups/ListAllChannelGroupEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/channel_groups/ListAllChannelGroupEndpoint.kt index d9bf4ec709..591db078d6 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/channel_groups/ListAllChannelGroupEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/channel_groups/ListAllChannelGroupEndpoint.kt @@ -2,10 +2,14 @@ package com.pubnub.internal.endpoints.channel_groups import com.pubnub.api.endpoints.channel_groups.ListAllChannelGroup import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.channel_group.PNChannelGroupsListAllResult import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.models.server.Envelope import retrofit2.Call import retrofit2.Response @@ -16,7 +20,20 @@ import retrofit2.Response class ListAllChannelGroupEndpoint internal constructor(pubnub: PubNubImpl) : EndpointCore>, PNChannelGroupsListAllResult>(pubnub), ListAllChannelGroup { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun doWork(queryParams: HashMap): Call>> { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "queryParams" to queryParams + ) + ), + details = "ListAllChannelGroup API call", + ) + ) + return retrofitManager.channelGroupService .listAllChannelGroup( configuration.subscribeKey, diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/channel_groups/RemoveChannelChannelGroupEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/channel_groups/RemoveChannelChannelGroupEndpoint.kt index 2e9bda8b04..fa8b2af8a9 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/channel_groups/RemoveChannelChannelGroupEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/channel_groups/RemoveChannelChannelGroupEndpoint.kt @@ -4,10 +4,14 @@ import com.pubnub.api.PubNubError import com.pubnub.api.PubNubException import com.pubnub.api.endpoints.channel_groups.RemoveChannelChannelGroup import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.channel_group.PNChannelGroupsRemoveChannelResult import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.toCsv import retrofit2.Call import retrofit2.Response @@ -20,6 +24,8 @@ class RemoveChannelChannelGroupEndpoint internal constructor( override val channelGroup: String, override val channels: List, ) : EndpointCore(pubnub), RemoveChannelChannelGroup { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun getAffectedChannels() = channels override fun getAffectedChannelGroups() = listOf(channelGroup) @@ -35,6 +41,19 @@ class RemoveChannelChannelGroupEndpoint internal constructor( } override fun doWork(queryParams: HashMap): Call { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "channelGroup" to channelGroup, + "channels" to channels, + "queryParams" to queryParams + ) + ), + details = "RemoveChannelChannelGroup API call", + ) + ) + addQueryParams(queryParams) return retrofitManager.channelGroupService diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/files/DeleteFileEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/files/DeleteFileEndpoint.kt index 282f3d5c6f..5fc84d6ba1 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/files/DeleteFileEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/files/DeleteFileEndpoint.kt @@ -4,10 +4,14 @@ import com.pubnub.api.PubNubError import com.pubnub.api.PubNubException import com.pubnub.api.endpoints.files.DeleteFile import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.files.PNDeleteFileResult import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import retrofit2.Call import retrofit2.Response @@ -20,6 +24,8 @@ class DeleteFileEndpoint( private val fileId: String, pubNub: PubNubImpl, ) : EndpointCore(pubNub), DeleteFile { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + @Throws(PubNubException::class) override fun validateParams() { if (channel.isEmpty()) { @@ -28,14 +34,29 @@ class DeleteFileEndpoint( } @Throws(PubNubException::class) - override fun doWork(queryParams: HashMap): Call = - retrofitManager.filesService.deleteFile( + override fun doWork(queryParams: HashMap): Call { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "channel" to channel, + "fileName" to fileName, + "fileId" to fileId, + "queryParams" to queryParams + ) + ), + details = "DeleteFile API call", + ) + ) + + return retrofitManager.filesService.deleteFile( configuration.subscribeKey, channel, fileId, fileName, queryParams, ) + } @Throws(PubNubException::class) override fun createResponse(input: Response): PNDeleteFileResult = diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/files/DownloadFileEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/files/DownloadFileEndpoint.kt index 1e51c78e4d..1d7d90b3a0 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/files/DownloadFileEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/files/DownloadFileEndpoint.kt @@ -5,10 +5,14 @@ import com.pubnub.api.PubNubException import com.pubnub.api.crypto.CryptoModule import com.pubnub.api.endpoints.files.DownloadFile import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.files.PNDownloadFileResult import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import okhttp3.ResponseBody import retrofit2.Call import retrofit2.Response @@ -23,6 +27,8 @@ class DownloadFileEndpoint( private val cryptoModule: CryptoModule? = null, pubNub: PubNubImpl, ) : EndpointCore(pubNub), DownloadFile { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + @Throws(PubNubException::class) override fun validateParams() { if (channel.isEmpty()) { @@ -31,14 +37,30 @@ class DownloadFileEndpoint( } @Throws(PubNubException::class) - override fun doWork(queryParams: HashMap): Call = - retrofitManager.filesService.downloadFile( + override fun doWork(queryParams: HashMap): Call { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "channel" to channel, + "fileName" to fileName, + "fileId" to fileId, + "cryptoModule" to (cryptoModule != null).toString(), + "queryParams" to queryParams + ) + ), + details = "DownloadFile API call", + ) + ) + + return retrofitManager.filesService.downloadFile( configuration.subscribeKey, channel, fileId, fileName, queryParams, ) + } @Throws(PubNubException::class) override fun createResponse(input: Response): PNDownloadFileResult { diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/files/GenerateUploadUrlEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/files/GenerateUploadUrlEndpoint.kt index 2d2056af19..a7dbab028c 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/files/GenerateUploadUrlEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/files/GenerateUploadUrlEndpoint.kt @@ -4,9 +4,13 @@ import com.pubnub.api.PubNubError import com.pubnub.api.PubNubException import com.pubnub.api.endpoints.remoteaction.ExtendedRemoteAction import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.models.server.files.FileUploadRequestDetails import com.pubnub.internal.models.server.files.FormField import com.pubnub.internal.models.server.files.GenerateUploadUrlPayload @@ -19,6 +23,8 @@ internal class GenerateUploadUrlEndpoint( private val fileName: String, pubNub: PubNubImpl, ) : EndpointCore(pubNub) { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + @Throws(PubNubException::class) override fun validateParams() { if (channel.isEmpty()) { @@ -53,6 +59,19 @@ internal class GenerateUploadUrlEndpoint( } override fun doWork(queryParams: HashMap): Call { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "channel" to channel, + "fileName" to fileName, + "queryParams" to queryParams + ) + ), + details = "GenerateUploadUrl API call", + ) + ) + return retrofitManager.filesService.generateUploadUrl( configuration.subscribeKey, channel, diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/files/GetFileUrlEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/files/GetFileUrlEndpoint.kt index 171ebc0425..86591058c5 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/files/GetFileUrlEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/files/GetFileUrlEndpoint.kt @@ -4,12 +4,16 @@ import com.pubnub.api.PubNubError import com.pubnub.api.PubNubException import com.pubnub.api.endpoints.files.GetFileUrl import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.files.PNFileUrlResult import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.api.v2.callbacks.Result import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl import com.pubnub.internal.PubNubUtil +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import okhttp3.ResponseBody import retrofit2.Call import retrofit2.Response @@ -26,6 +30,7 @@ class GetFileUrlEndpoint( private val fileId: String, pubNub: PubNubImpl, ) : EndpointCore(pubNub), GetFileUrl { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) private lateinit var cachedCallback: Consumer> private val executorService: ExecutorService = retrofitManager.getTransactionClientExecutorService() ?: Executors.newSingleThreadExecutor() @@ -42,6 +47,19 @@ class GetFileUrlEndpoint( // properly constructed url the code creates a request which isn't executed @Throws(PubNubException::class) override fun sync(): PNFileUrlResult { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "channel" to channel, + "fileName" to fileName, + "fileId" to fileId + ) + ), + details = "GetFileUrl API call", + ) + ) + return try { val baseParams: Map = createBaseParams() val call: Call = diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/files/ListFilesEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/files/ListFilesEndpoint.kt index e5e9868c82..9b87579f57 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/files/ListFilesEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/files/ListFilesEndpoint.kt @@ -4,11 +4,15 @@ import com.pubnub.api.PubNubError import com.pubnub.api.PubNubException import com.pubnub.api.endpoints.files.ListFiles import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.files.PNListFilesResult import com.pubnub.api.models.consumer.objects.PNPage import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.models.server.files.ListFilesResult import retrofit2.Call import retrofit2.Response @@ -22,6 +26,8 @@ class ListFilesEndpoint( private val next: PNPage.PNNext? = null, pubNub: PubNubImpl, ) : EndpointCore(pubNub), ListFiles { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + @Throws(PubNubException::class) override fun validateParams() { if (channel.isEmpty()) { @@ -41,6 +47,20 @@ class ListFilesEndpoint( @Throws(PubNubException::class) override fun doWork(queryParams: HashMap): Call { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "channel" to channel, + "limit" to (limit ?: DEFAULT_LIMIT), + "next" to (next?.pageHash ?: ""), + "queryParams" to queryParams + ) + ), + details = "ListFiles API call", + ) + ) + queryParams[LIMIT_QUERY_PARAM] = (limit ?: DEFAULT_LIMIT).toString() if (next != null) { queryParams[NEXT_PAGE_QUERY_PARAM] = next.pageHash diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/files/PublishFileMessageEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/files/PublishFileMessageEndpoint.kt index 46d30e7645..2bad1c64ce 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/files/PublishFileMessageEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/files/PublishFileMessageEndpoint.kt @@ -5,6 +5,8 @@ import com.pubnub.api.PubNubException import com.pubnub.api.endpoints.files.PublishFileMessage import com.pubnub.api.endpoints.remoteaction.ExtendedRemoteAction import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.files.PNBaseFile import com.pubnub.api.models.consumer.files.PNPublishFileMessageResult import com.pubnub.api.retry.RetryableEndpointGroup @@ -14,6 +16,8 @@ import com.pubnub.internal.crypto.encryptString import com.pubnub.internal.endpoints.pubsub.PublishEndpoint.Companion.CUSTOM_MESSAGE_TYPE_QUERY_PARAM import com.pubnub.internal.extension.numericString import com.pubnub.internal.extension.quoted +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.models.server.files.FileUploadNotification import retrofit2.Call import retrofit2.Response @@ -32,6 +36,7 @@ open class PublishFileMessageEndpoint( private val customMessageType: String? = null, pubNub: PubNubImpl, ) : EndpointCore, PNPublishFileMessageResult>(pubNub), PublishFileMessage { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) private val pnFile = PNBaseFile(fileId, fileName) @Throws(PubNubException::class) @@ -43,8 +48,27 @@ open class PublishFileMessageEndpoint( @Throws(PubNubException::class) override fun doWork(queryParams: HashMap): Call> { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "channel" to channel, + "fileName" to pnFile.name, + "fileId" to pnFile.id, + "message" to (message ?: ""), + "meta" to (meta ?: ""), + "ttl" to (ttl ?: 0), + "shouldStore" to (shouldStore ?: true), + "customMessageType" to (customMessageType ?: ""), + "queryParams" to queryParams + ) + ), + details = "PublishFileMessage API call", + ) + ) + val stringifiedMessage: String = pubnub.mapper.toJson(FileUploadNotification(message, pnFile)) - val messageAsString = configuration.cryptoModule?.encryptString(stringifiedMessage)?.quoted() ?: stringifiedMessage + val messageAsString = pubnub.cryptoModuleWithLogConfig?.encryptString(stringifiedMessage)?.quoted() ?: stringifiedMessage meta?.let { val stringifiedMeta: String = pubnub.mapper.toJson(it) queryParams["meta"] = stringifiedMeta diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/files/SendFileEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/files/SendFileEndpoint.kt index b6e0c0e21d..d0e7059046 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/files/SendFileEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/files/SendFileEndpoint.kt @@ -92,14 +92,14 @@ class SendFileEndpoint internal constructor( cryptoModule?.encryptStream(InputStreamSeparator(inputStream))?.use { it.readBytes() } ?: inputStream.readBytes() - return ComposableRemoteAction.firstDo(generateUploadUrlFactory.create(channel, fileName)) // generateUrl + return ComposableRemoteAction.firstDo(generateUploadUrlFactory.create(channel, fileName)) // 1. generateUrl .then { res -> result.set(res) - sendFileToS3Factory.create(fileName, content, res) // upload to s3 + sendFileToS3Factory.create(fileName, content, res) // 2. upload to s3 }.checkpoint().then { val details = result.get() RetryingRemoteAction.autoRetry( - publishFileMessageFactory.create( + publishFileMessageFactory.create( // 3. PublishFileMessage channel = channel, fileName = details.data.name, fileId = details.data.id, diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/files/UploadFileEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/files/UploadFileEndpoint.kt index b773734859..e14301eed3 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/files/UploadFileEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/files/UploadFileEndpoint.kt @@ -4,8 +4,12 @@ import com.pubnub.api.PubNubError import com.pubnub.api.PubNubException import com.pubnub.api.endpoints.remoteaction.ExtendedRemoteAction import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogConfig +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.v2.callbacks.Result import com.pubnub.internal.PubNubImpl +import com.pubnub.internal.logging.LoggerManager import com.pubnub.internal.models.server.files.FileUploadRequestDetails import com.pubnub.internal.models.server.files.FormField import com.pubnub.internal.services.S3Service @@ -13,7 +17,6 @@ import okhttp3.MediaType import okhttp3.MediaType.Companion.toMediaType import okhttp3.MultipartBody import okhttp3.RequestBody.Companion.toRequestBody -import org.slf4j.LoggerFactory import retrofit2.Call import retrofit2.Callback import retrofit2.Response @@ -32,8 +35,10 @@ internal class UploadFileEndpoint( private val key: FormField, private val formParams: List, private val baseUrl: String, + private val logConfig: LogConfig ) : ExtendedRemoteAction { private var call: Call? = null + private val log = LoggerManager.instance.getLogger(logConfig, this::class.java) @Throws(PubNubException::class) private fun prepareCall(): Call { @@ -58,7 +63,11 @@ internal class UploadFileEndpoint( try { contentType.toMediaType() } catch (t: Throwable) { - log.warn("Content-Type: $contentType was not recognized by MediaType.get", t) + log.warn( + LogMessage( + message = LogMessageContent.Text("Content-Type: $contentType was not recognized by MediaType.get: ${t.message}"), + ) + ) APPLICATION_OCTET_STREAM } } @@ -182,6 +191,7 @@ internal class UploadFileEndpoint( fileUploadRequestDetails.keyFormField, fileUploadRequestDetails.formFields, fileUploadRequestDetails.url, + pubNub.logConfig ) } } @@ -190,7 +200,6 @@ internal class UploadFileEndpoint( private val APPLICATION_OCTET_STREAM = "application/octet-stream".toMediaType() private const val CONTENT_TYPE_HEADER = "Content-Type" private const val FILE_PART_MULTIPART = "file" - private val log = LoggerFactory.getLogger(UploadFileEndpoint::class.java) private fun addFormParamsWithKeyFirst( keyValue: FormField, diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/message_actions/AddMessageActionEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/message_actions/AddMessageActionEndpoint.kt index fec91da582..e61adb4072 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/message_actions/AddMessageActionEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/message_actions/AddMessageActionEndpoint.kt @@ -5,11 +5,15 @@ import com.pubnub.api.PubNubError import com.pubnub.api.PubNubException import com.pubnub.api.endpoints.message_actions.AddMessageAction import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.message_actions.PNAddMessageActionResult import com.pubnub.api.models.consumer.message_actions.PNMessageAction import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.models.server.objects_api.EntityEnvelope import retrofit2.Call import retrofit2.Response @@ -23,6 +27,8 @@ class AddMessageActionEndpoint internal constructor( override val channel: String, override val messageAction: PNMessageAction, ) : EndpointCore, PNAddMessageActionResult>(pubnub), AddMessageAction { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun validateParams() { super.validateParams() if (channel.isBlank()) { @@ -39,6 +45,21 @@ class AddMessageActionEndpoint internal constructor( override fun getAffectedChannels() = listOf(channel) override fun doWork(queryParams: HashMap): Call> { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "channel" to channel, + "messageActionType" to messageAction.type, + "messageActionValue" to messageAction.value, + "messageTimetoken" to messageAction.messageTimetoken, + "queryParams" to queryParams + ) + ), + details = "AddMessageAction API call", + ) + ) + val body = JsonObject().apply { addProperty("type", messageAction.type) diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/message_actions/GetMessageActionsEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/message_actions/GetMessageActionsEndpoint.kt index 07b3455acd..7140160ab4 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/message_actions/GetMessageActionsEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/message_actions/GetMessageActionsEndpoint.kt @@ -4,11 +4,15 @@ import com.pubnub.api.PubNubError import com.pubnub.api.PubNubException import com.pubnub.api.endpoints.message_actions.GetMessageActions import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.PNBoundedPage import com.pubnub.api.models.consumer.message_actions.PNGetMessageActionsResult import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import retrofit2.Call import retrofit2.Response import java.util.Locale @@ -21,6 +25,8 @@ class GetMessageActionsEndpoint internal constructor( override val channel: String, override val page: PNBoundedPage, ) : EndpointCore(pubnub), GetMessageActions { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun validateParams() { super.validateParams() if (channel.isBlank()) { @@ -31,6 +37,21 @@ class GetMessageActionsEndpoint internal constructor( override fun getAffectedChannels() = listOf(channel) override fun doWork(queryParams: HashMap): Call { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "channel" to channel, + "pageStart" to (page.start ?: ""), + "pageEnd" to (page.end ?: ""), + "pageLimit" to (page.limit ?: 100), + "queryParams" to queryParams + ) + ), + details = "GetMessageActions API call", + ) + ) + addQueryParams(queryParams) return retrofitManager.messageActionService diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/message_actions/RemoveMessageActionEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/message_actions/RemoveMessageActionEndpoint.kt index 82126bb310..589876afe7 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/message_actions/RemoveMessageActionEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/message_actions/RemoveMessageActionEndpoint.kt @@ -4,10 +4,14 @@ import com.pubnub.api.PubNubError import com.pubnub.api.PubNubException import com.pubnub.api.endpoints.message_actions.RemoveMessageAction import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.message_actions.PNRemoveMessageActionResult import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import retrofit2.Call import retrofit2.Response import java.util.Locale @@ -21,6 +25,8 @@ class RemoveMessageActionEndpoint internal constructor( override val messageTimetoken: Long, override val actionTimetoken: Long, ) : EndpointCore(pubnub), RemoveMessageAction { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun validateParams() { super.validateParams() if (channel.isBlank()) { @@ -31,6 +37,20 @@ class RemoveMessageActionEndpoint internal constructor( override fun getAffectedChannels() = listOf(channel) override fun doWork(queryParams: HashMap): Call { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "channel" to channel, + "messageTimetoken" to messageTimetoken, + "actionTimetoken" to actionTimetoken, + "queryParams" to queryParams + ) + ), + details = "RemoveMessageAction API call", + ) + ) + return retrofitManager.messageActionService .deleteMessageAction( subKey = configuration.subscribeKey, diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/channel/GetAllChannelMetadataEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/channel/GetAllChannelMetadataEndpoint.kt index 064635fe46..3ff7db1a0f 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/channel/GetAllChannelMetadataEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/channel/GetAllChannelMetadataEndpoint.kt @@ -2,6 +2,8 @@ package com.pubnub.internal.endpoints.objects.channel import com.pubnub.api.endpoints.objects.channel.GetAllChannelMetadata import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.objects.PNPage import com.pubnub.api.models.consumer.objects.channel.PNChannelMetadata import com.pubnub.api.models.consumer.objects.channel.PNChannelMetadataArrayResult @@ -10,6 +12,8 @@ import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl import com.pubnub.internal.endpoints.objects.internal.CollectionQueryParameters import com.pubnub.internal.endpoints.objects.internal.IncludeQueryParam +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.models.server.objects_api.EntityArrayEnvelope import retrofit2.Call import retrofit2.Response @@ -23,7 +27,19 @@ class GetAllChannelMetadataEndpoint internal constructor( private val includeQueryParam: IncludeQueryParam, ) : EndpointCore, PNChannelMetadataArrayResult>(pubnub), GetAllChannelMetadata { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun doWork(queryParams: HashMap): Call> { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "queryParams" to queryParams + ) + ), + details = "GetAllChannelMetadata API call", + ) + ) val params = queryParams + collectionQueryParameters.createCollectionQueryParams() + includeQueryParam.createIncludeQueryParams() diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/channel/GetChannelMetadataEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/channel/GetChannelMetadataEndpoint.kt index e0b7ae22de..945a3ddf93 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/channel/GetChannelMetadataEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/channel/GetChannelMetadataEndpoint.kt @@ -2,12 +2,16 @@ package com.pubnub.internal.endpoints.objects.channel import com.pubnub.api.endpoints.objects.channel.GetChannelMetadata import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.objects.channel.PNChannelMetadata import com.pubnub.api.models.consumer.objects.channel.PNChannelMetadataResult import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl import com.pubnub.internal.endpoints.objects.internal.IncludeQueryParam +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.models.server.objects_api.EntityEnvelope import retrofit2.Call import retrofit2.Response @@ -20,7 +24,20 @@ class GetChannelMetadataEndpoint internal constructor( private val channel: String, private val includeQueryParam: IncludeQueryParam, ) : EndpointCore, PNChannelMetadataResult>(pubnub), GetChannelMetadata { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun doWork(queryParams: HashMap): Call> { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "channel" to channel, + "queryParams" to queryParams + ) + ), + details = "GetChannelMetadata API call", + ) + ) val params = queryParams + includeQueryParam.createIncludeQueryParams() return retrofitManager.objectsService.getChannelMetadata( subKey = configuration.subscribeKey, diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/channel/RemoveChannelMetadataEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/channel/RemoveChannelMetadataEndpoint.kt index 8e0c311bc0..61691660f8 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/channel/RemoveChannelMetadataEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/channel/RemoveChannelMetadataEndpoint.kt @@ -2,10 +2,14 @@ package com.pubnub.internal.endpoints.objects.channel import com.pubnub.api.endpoints.objects.channel.RemoveChannelMetadata import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.objects.PNRemoveMetadataResult import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.models.server.objects_api.EntityEnvelope import retrofit2.Call import retrofit2.Response @@ -14,7 +18,20 @@ class RemoveChannelMetadataEndpoint( pubnub: PubNubImpl, private val channel: String, ) : EndpointCore, PNRemoveMetadataResult>(pubnub), RemoveChannelMetadata { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun doWork(queryParams: HashMap): Call> { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "channel" to channel, + "queryParams" to queryParams + ) + ), + details = "RemoveChannelMetadata API call", + ) + ) return retrofitManager.objectsService.deleteChannelMetadata( subKey = configuration.subscribeKey, channel = channel, diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/channel/SetChannelMetadataEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/channel/SetChannelMetadataEndpoint.kt index a89ac1a6cc..820faacc82 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/channel/SetChannelMetadataEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/channel/SetChannelMetadataEndpoint.kt @@ -2,12 +2,16 @@ package com.pubnub.internal.endpoints.objects.channel import com.pubnub.api.endpoints.objects.channel.SetChannelMetadata import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.objects.channel.PNChannelMetadata import com.pubnub.api.models.consumer.objects.channel.PNChannelMetadataResult import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl import com.pubnub.internal.endpoints.objects.internal.IncludeQueryParam +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.models.server.objects_api.ChannelMetadataInput import com.pubnub.internal.models.server.objects_api.EntityEnvelope import retrofit2.Call @@ -28,7 +32,28 @@ class SetChannelMetadataEndpoint internal constructor( private val ifMatchesEtag: String?, ) : EndpointCore, PNChannelMetadataResult>(pubnub), SetChannelMetadata { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun doWork(queryParams: HashMap): Call> { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "channel" to channel, + "name" to (name ?: ""), + "description" to (description ?: ""), + "custom" to (custom ?: ""), + "type" to (type ?: ""), + "status" to (status ?: ""), + "ifMatchesEtag" to (ifMatchesEtag ?: ""), + "includeQueryParam" to includeQueryParam, + "queryParams" to queryParams + ) + ), + details = "SetChannelMetadata API call", + ) + ) + val params = queryParams + includeQueryParam.createIncludeQueryParams() return retrofitManager.objectsService.setChannelMetadata( subKey = configuration.subscribeKey, diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/member/GetChannelMembersEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/member/GetChannelMembersEndpoint.kt index 611bedbce2..4d7483d2f0 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/member/GetChannelMembersEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/member/GetChannelMembersEndpoint.kt @@ -2,6 +2,8 @@ package com.pubnub.internal.endpoints.objects.member import com.pubnub.api.endpoints.objects.member.GetChannelMembers import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.objects.member.PNMember import com.pubnub.api.models.consumer.objects.member.PNMemberArrayResult import com.pubnub.api.retry.RetryableEndpointGroup @@ -10,6 +12,8 @@ import com.pubnub.internal.PubNubImpl import com.pubnub.internal.endpoints.objects.internal.CollectionQueryParameters import com.pubnub.internal.endpoints.objects.internal.IncludeQueryParam import com.pubnub.internal.extension.toPNMemberArrayResult +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.models.server.objects_api.EntityArrayEnvelope import retrofit2.Call import retrofit2.Response @@ -23,7 +27,20 @@ class GetChannelMembersEndpoint internal constructor( private val collectionQueryParameters: CollectionQueryParameters, private val includeQueryParam: IncludeQueryParam, ) : EndpointCore, PNMemberArrayResult>(pubnub), GetChannelMembers { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun doWork(queryParams: HashMap): Call> { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "channel" to channel, + "queryParams" to queryParams + ) + ), + details = "GetChannelMembers API call", + ) + ) val params = queryParams + collectionQueryParameters.createCollectionQueryParams() + includeQueryParam.createIncludeQueryParams() diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/member/ManageChannelMembersEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/member/ManageChannelMembersEndpoint.kt index 0d26a331b3..048de5f3d6 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/member/ManageChannelMembersEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/member/ManageChannelMembersEndpoint.kt @@ -2,6 +2,8 @@ package com.pubnub.internal.endpoints.objects.member import com.pubnub.api.endpoints.objects.member.ManageChannelMembers import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.objects.member.MemberInput import com.pubnub.api.models.consumer.objects.member.PNMember import com.pubnub.api.models.consumer.objects.member.PNMemberArrayResult @@ -11,6 +13,8 @@ import com.pubnub.internal.PubNubImpl import com.pubnub.internal.endpoints.objects.internal.CollectionQueryParameters import com.pubnub.internal.endpoints.objects.internal.IncludeQueryParam import com.pubnub.internal.extension.toPNMemberArrayResult +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.models.server.objects_api.ChangeMemberInput import com.pubnub.internal.models.server.objects_api.EntityArrayEnvelope import com.pubnub.internal.models.server.objects_api.ServerMemberInput @@ -29,7 +33,22 @@ class ManageChannelMembersEndpoint( private val collectionQueryParameters: CollectionQueryParameters, private val includeQueryParam: IncludeQueryParam, ) : EndpointCore, PNMemberArrayResult>(pubnub), ManageChannelMembers { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun doWork(queryParams: HashMap): Call> { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "channel" to channel, + "userToSet" to userToSet, + "userIdsRemove" to userIdsRemove, + "queryParams" to queryParams + ) + ), + details = "ManageChannelMembers API call", + ) + ) val params = queryParams + collectionQueryParameters.createCollectionQueryParams() + includeQueryParam.createIncludeQueryParams() diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/membership/GetMembershipsEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/membership/GetMembershipsEndpoint.kt index a4e9b33ca5..83f8ee42ed 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/membership/GetMembershipsEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/membership/GetMembershipsEndpoint.kt @@ -2,6 +2,8 @@ package com.pubnub.internal.endpoints.objects.membership import com.pubnub.api.endpoints.objects.membership.GetMemberships import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.objects.membership.PNChannelMembership import com.pubnub.api.models.consumer.objects.membership.PNChannelMembershipArrayResult import com.pubnub.api.retry.RetryableEndpointGroup @@ -10,6 +12,8 @@ import com.pubnub.internal.PubNubImpl import com.pubnub.internal.endpoints.objects.internal.CollectionQueryParameters import com.pubnub.internal.endpoints.objects.internal.IncludeQueryParam import com.pubnub.internal.extension.toPNChannelMembershipArrayResult +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.models.server.objects_api.EntityArrayEnvelope import retrofit2.Call import retrofit2.Response @@ -24,7 +28,20 @@ class GetMembershipsEndpoint internal constructor( private val includeQueryParam: IncludeQueryParam, ) : EndpointCore, PNChannelMembershipArrayResult>(pubnub), GetMemberships { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun doWork(queryParams: HashMap): Call> { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "uuid" to uuid, + "queryParams" to queryParams + ) + ), + details = "GetMemberships API call", + ) + ) val params = queryParams + collectionQueryParameters.createCollectionQueryParams() + includeQueryParam.createIncludeQueryParams() diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/membership/ManageMembershipsEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/membership/ManageMembershipsEndpoint.kt index 90cf97a579..76ebb1c3d5 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/membership/ManageMembershipsEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/membership/ManageMembershipsEndpoint.kt @@ -2,6 +2,8 @@ package com.pubnub.internal.endpoints.objects.membership import com.pubnub.api.endpoints.objects.membership.ManageMemberships import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.objects.membership.ChannelMembershipInput import com.pubnub.api.models.consumer.objects.membership.PNChannelMembership import com.pubnub.api.models.consumer.objects.membership.PNChannelMembershipArrayResult @@ -11,6 +13,8 @@ import com.pubnub.internal.PubNubImpl import com.pubnub.internal.endpoints.objects.internal.CollectionQueryParameters import com.pubnub.internal.endpoints.objects.internal.IncludeQueryParam import com.pubnub.internal.extension.toPNChannelMembershipArrayResult +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.models.server.objects_api.ChangeMembershipInput import com.pubnub.internal.models.server.objects_api.ChannelId import com.pubnub.internal.models.server.objects_api.EntityArrayEnvelope @@ -30,7 +34,22 @@ class ManageMembershipsEndpoint internal constructor( private val includeQueryParam: IncludeQueryParam, ) : EndpointCore, PNChannelMembershipArrayResult>(pubnub), ManageMemberships { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun doWork(queryParams: HashMap): Call> { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "uuid" to uuid, + "channelsToSet" to channelsToSet, + "channelsToRemove" to channelsToRemove, + "queryParams" to queryParams + ) + ), + details = "ManageMemberships API call", + ) + ) val params = queryParams + collectionQueryParameters.createCollectionQueryParams() + includeQueryParam.createIncludeQueryParams() diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/uuid/GetAllUUIDMetadataEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/uuid/GetAllUUIDMetadataEndpoint.kt index 33a7159959..b5fa964de8 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/uuid/GetAllUUIDMetadataEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/uuid/GetAllUUIDMetadataEndpoint.kt @@ -2,6 +2,8 @@ package com.pubnub.internal.endpoints.objects.uuid import com.pubnub.api.endpoints.objects.uuid.GetAllUUIDMetadata import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.objects.PNPage import com.pubnub.api.models.consumer.objects.uuid.PNUUIDMetadata import com.pubnub.api.models.consumer.objects.uuid.PNUUIDMetadataArrayResult @@ -10,6 +12,8 @@ import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl import com.pubnub.internal.endpoints.objects.internal.CollectionQueryParameters import com.pubnub.internal.endpoints.objects.internal.IncludeQueryParam +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.models.server.objects_api.EntityArrayEnvelope import retrofit2.Call import retrofit2.Response @@ -23,7 +27,19 @@ class GetAllUUIDMetadataEndpoint internal constructor( private val withInclude: IncludeQueryParam, ) : EndpointCore, PNUUIDMetadataArrayResult>(pubnub), GetAllUUIDMetadata { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun doWork(queryParams: HashMap): Call> { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "queryParams" to queryParams + ) + ), + details = "GetAllUUIDMetadata API call", + ) + ) val params = queryParams + collectionQueryParameters.createCollectionQueryParams() + withInclude.createIncludeQueryParams() diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/uuid/GetUUIDMetadataEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/uuid/GetUUIDMetadataEndpoint.kt index c72bf298b4..96686cd6ca 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/uuid/GetUUIDMetadataEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/uuid/GetUUIDMetadataEndpoint.kt @@ -2,12 +2,16 @@ package com.pubnub.internal.endpoints.objects.uuid import com.pubnub.api.endpoints.objects.uuid.GetUUIDMetadata import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.objects.uuid.PNUUIDMetadata import com.pubnub.api.models.consumer.objects.uuid.PNUUIDMetadataResult import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl import com.pubnub.internal.endpoints.objects.internal.IncludeQueryParam +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.models.server.objects_api.EntityEnvelope import retrofit2.Call import retrofit2.Response @@ -20,7 +24,20 @@ class GetUUIDMetadataEndpoint internal constructor( override val uuid: String, private val includeQueryParam: IncludeQueryParam, ) : EndpointCore, PNUUIDMetadataResult>(pubnub), GetUUIDMetadata { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun doWork(queryParams: HashMap): Call> { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "uuid" to uuid, + "queryParams" to queryParams + ) + ), + details = "GetUUIDMetadata API call", + ) + ) val params = queryParams + includeQueryParam.createIncludeQueryParams() return retrofitManager.objectsService.getUUIDMetadata( subKey = configuration.subscribeKey, diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/uuid/RemoveUUIDMetadataEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/uuid/RemoveUUIDMetadataEndpoint.kt index 45ef82e1cb..22cc4780e9 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/uuid/RemoveUUIDMetadataEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/uuid/RemoveUUIDMetadataEndpoint.kt @@ -2,10 +2,14 @@ package com.pubnub.internal.endpoints.objects.uuid import com.pubnub.api.endpoints.objects.uuid.RemoveUUIDMetadata import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.objects.PNRemoveMetadataResult import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.models.server.objects_api.EntityEnvelope import retrofit2.Call import retrofit2.Response @@ -14,7 +18,20 @@ class RemoveUUIDMetadataEndpoint( pubnub: PubNubImpl, override val uuid: String? = null, ) : EndpointCore, PNRemoveMetadataResult>(pubnub), RemoveUUIDMetadata { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun doWork(queryParams: HashMap): Call> { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "uuid" to (uuid ?: configuration.userId.value), + "queryParams" to queryParams + ) + ), + details = "RemoveUUIDMetadata API call", + ) + ) return retrofitManager.objectsService.deleteUUIDMetadata( subKey = configuration.subscribeKey, uuid = uuid ?: configuration.userId.value, diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/uuid/SetUUIDMetadataEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/uuid/SetUUIDMetadataEndpoint.kt index 6d00fc11b5..f17e40b017 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/uuid/SetUUIDMetadataEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/objects/uuid/SetUUIDMetadataEndpoint.kt @@ -2,12 +2,16 @@ package com.pubnub.internal.endpoints.objects.uuid import com.pubnub.api.endpoints.objects.uuid.SetUUIDMetadata import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.objects.uuid.PNUUIDMetadata import com.pubnub.api.models.consumer.objects.uuid.PNUUIDMetadataResult import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl import com.pubnub.internal.endpoints.objects.internal.IncludeQueryParam +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.models.server.objects_api.EntityEnvelope import com.pubnub.internal.models.server.objects_api.UUIDMetadataInput import retrofit2.Call @@ -29,7 +33,28 @@ class SetUUIDMetadataEndpoint internal constructor( private val status: String?, private val ifMatchesEtag: String?, ) : EndpointCore, PNUUIDMetadataResult>(pubnub), SetUUIDMetadata { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun doWork(queryParams: HashMap): Call> { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "uuid" to (uuid ?: configuration.userId.value), + "name" to (name ?: ""), + "externalId" to (externalId ?: ""), + "profileUrl" to (profileUrl ?: ""), + "email" to (email ?: ""), + "custom" to (custom ?: ""), + "type" to (type ?: ""), + "status" to (status ?: ""), + "ifMatchesEtag" to (ifMatchesEtag ?: ""), + "queryParams" to queryParams + ) + ), + details = "SetUUIDMetadata API call", + ) + ) val params = queryParams + withInclude.createIncludeQueryParams() return retrofitManager.objectsService.setUUIDMetadata( subKey = configuration.subscribeKey, diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/presence/GetStateEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/presence/GetStateEndpoint.kt index dbf2236826..2670840b3a 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/presence/GetStateEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/presence/GetStateEndpoint.kt @@ -5,10 +5,14 @@ import com.pubnub.api.PubNubError import com.pubnub.api.PubNubException import com.pubnub.api.endpoints.presence.GetState import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.presence.PNGetStateResult import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.models.server.Envelope import com.pubnub.internal.toCsv import retrofit2.Call @@ -23,6 +27,8 @@ class GetStateEndpoint internal constructor( override val channelGroups: List, override val uuid: String = pubnub.configuration.userId.value, ) : EndpointCore, PNGetStateResult>(pubnub), GetState { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun getAffectedChannels() = channels override fun getAffectedChannelGroups() = channelGroups @@ -35,6 +41,20 @@ class GetStateEndpoint internal constructor( } override fun doWork(queryParams: HashMap): Call> { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "channels" to channels, + "channelGroups" to channelGroups, + "uuid" to uuid, + "queryParams" to queryParams + ) + ), + details = "GetState API call", + ) + ) + addQueryParams(queryParams) return retrofitManager.presenceService.getState( diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/presence/HeartbeatEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/presence/HeartbeatEndpoint.kt index 5a851548ee..4cac9ab604 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/presence/HeartbeatEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/presence/HeartbeatEndpoint.kt @@ -3,10 +3,14 @@ package com.pubnub.internal.endpoints.presence import com.pubnub.api.PubNubError import com.pubnub.api.PubNubException import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl import com.pubnub.internal.PubNubUtil +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import retrofit2.Call import retrofit2.Response @@ -16,6 +20,8 @@ class HeartbeatEndpoint internal constructor( val channelGroups: List = listOf(), val state: Any? = null, ) : EndpointCore(pubnub) { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun getAffectedChannels() = channels override fun getAffectedChannelGroups() = channelGroups @@ -33,6 +39,20 @@ class HeartbeatEndpoint internal constructor( } override fun doWork(queryParams: HashMap): Call { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "channels" to channels, + "channelGroups" to channelGroups, + "state" to (state ?: ""), + "queryParams" to queryParams + ) + ), + details = "Heartbeat API call", + ) + ) + addQueryParams(queryParams) val channelsCsv = diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/presence/HereNowEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/presence/HereNowEndpoint.kt index ba0d8ae308..4b4ef041d9 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/presence/HereNowEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/presence/HereNowEndpoint.kt @@ -3,12 +3,16 @@ package com.pubnub.internal.endpoints.presence import com.google.gson.JsonElement import com.pubnub.api.endpoints.presence.HereNow import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.presence.PNHereNowChannelData import com.pubnub.api.models.consumer.presence.PNHereNowOccupantData import com.pubnub.api.models.consumer.presence.PNHereNowResult import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.models.server.Envelope import com.pubnub.internal.toCsv import retrofit2.Call @@ -24,6 +28,8 @@ class HereNowEndpoint internal constructor( override val includeState: Boolean = false, override val includeUUIDs: Boolean = true, ) : EndpointCore, PNHereNowResult>(pubnub), HereNow { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + private fun isGlobalHereNow() = channels.isEmpty() && channelGroups.isEmpty() override fun getAffectedChannels() = channels @@ -31,6 +37,22 @@ class HereNowEndpoint internal constructor( override fun getAffectedChannelGroups() = channelGroups override fun doWork(queryParams: HashMap): Call> { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "channels" to channels, + "channelGroups" to channelGroups, + "includeState" to includeState, + "includeUUIDs" to includeUUIDs, + "isGlobalHereNow" to isGlobalHereNow(), + "queryParams" to queryParams + ) + ), + details = "HereNow API call", + ) + ) + addQueryParams(queryParams) return if (!isGlobalHereNow()) { diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/presence/LeaveEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/presence/LeaveEndpoint.kt index 5b17411c74..5da6ee27d2 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/presence/LeaveEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/presence/LeaveEndpoint.kt @@ -3,15 +3,21 @@ package com.pubnub.internal.endpoints.presence import com.pubnub.api.PubNubError import com.pubnub.api.PubNubException import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl import com.pubnub.internal.PubNubUtil +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.toCsv import retrofit2.Call import retrofit2.Response class LeaveEndpoint internal constructor(pubnub: PubNubImpl) : EndpointCore(pubnub) { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + var channels = emptyList() var channelGroups = emptyList() @@ -32,6 +38,19 @@ class LeaveEndpoint internal constructor(pubnub: PubNubImpl) : EndpointCore): Call { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "channels" to channels, + "channelGroups" to channelGroups, + "queryParams" to queryParams + ) + ), + details = "Leave API call", + ) + ) + addQueryParams(queryParams) return retrofitManager.presenceService.leave( configuration.subscribeKey, diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/presence/SetStateEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/presence/SetStateEndpoint.kt index 063ef3cf2e..841ec0e025 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/presence/SetStateEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/presence/SetStateEndpoint.kt @@ -6,10 +6,14 @@ import com.pubnub.api.PubNubError import com.pubnub.api.PubNubException import com.pubnub.api.endpoints.presence.SetState import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.presence.PNSetStateResult import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.models.server.Envelope import com.pubnub.internal.presence.eventengine.data.PresenceData import com.pubnub.internal.toCsv @@ -27,6 +31,8 @@ class SetStateEndpoint internal constructor( override val uuid: String = pubnub.configuration.userId.value, private val presenceData: PresenceData, ) : EndpointCore, PNSetStateResult>(pubnub), SetState { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun getAffectedChannels() = channels override fun getAffectedChannelGroups() = channelGroups @@ -39,6 +45,21 @@ class SetStateEndpoint internal constructor( } override fun doWork(queryParams: HashMap): Call> { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "channels" to channels, + "channelGroups" to channelGroups, + "state" to state, + "uuid" to uuid, + "queryParams" to queryParams + ) + ), + details = "SetState API call", + ) + ) + if (uuid == pubnub.configuration.userId.value) { val stateCopy = pubnub.mapper.fromJson(pubnub.mapper.toJson(state), JsonElement::class.java) presenceData.channelStates.putAll(channels.associateWith { stateCopy }) diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/presence/WhereNowEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/presence/WhereNowEndpoint.kt index 2f5268949b..6545bb4de0 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/presence/WhereNowEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/presence/WhereNowEndpoint.kt @@ -2,10 +2,14 @@ package com.pubnub.internal.endpoints.presence import com.pubnub.api.endpoints.presence.WhereNow import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.presence.PNWhereNowResult import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.models.server.Envelope import com.pubnub.internal.models.server.presence.WhereNowPayload import retrofit2.Call @@ -18,7 +22,21 @@ class WhereNowEndpoint internal constructor( pubnub: PubNubImpl, override val uuid: String = pubnub.configuration.userId.value, ) : EndpointCore, PNWhereNowResult>(pubnub), WhereNow { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun doWork(queryParams: HashMap): Call> { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "uuid" to uuid, + "queryParams" to queryParams + ) + ), + details = "WhereNow API call", + ) + ) + return retrofitManager.presenceService.whereNow( configuration.subscribeKey, uuid, diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/pubsub/PublishEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/pubsub/PublishEndpoint.kt index f118e984fa..5d68aab1d7 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/pubsub/PublishEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/pubsub/PublishEndpoint.kt @@ -4,6 +4,8 @@ import com.pubnub.api.PubNubError import com.pubnub.api.PubNubException import com.pubnub.api.endpoints.pubsub.Publish import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.PNPublishResult import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore @@ -12,6 +14,8 @@ import com.pubnub.internal.crypto.encryptString import com.pubnub.internal.extension.numericString import com.pubnub.internal.extension.quoted import com.pubnub.internal.extension.valueString +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import retrofit2.Call import retrofit2.Response @@ -27,8 +31,10 @@ class PublishEndpoint internal constructor( override val usePost: Boolean = false, override val replicate: Boolean = true, override val ttl: Int? = null, - override val customMessageType: String? = null + override val customMessageType: String? = null, ) : EndpointCore, PNPublishResult>(pubnub), Publish { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + companion object { internal const val CUSTOM_MESSAGE_TYPE_QUERY_PARAM = "custom_message_type" } @@ -43,6 +49,25 @@ class PublishEndpoint internal constructor( override fun getAffectedChannels() = listOf(channel) override fun doWork(queryParams: HashMap): Call> { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "message" to message, + "channel" to channel, + "shouldStore" to (shouldStore ?: true), + "meta" to (meta ?: ""), + "queryParams" to queryParams, + "usePost" to usePost, + "ttl" to (ttl ?: 0), + "replicate" to replicate, + "customMessageType" to (customMessageType ?: "") + ) + ), + details = "Publish API call" + ) + ) + addQueryParams(queryParams) return if (usePost) { @@ -58,7 +83,6 @@ class PublishEndpoint internal constructor( } else { // HTTP GET request val stringifiedMessage = getParamMessage(message) - retrofitManager.publishService.publish( configuration.publishKey, configuration.subscribeKey, @@ -100,10 +124,10 @@ class PublishEndpoint internal constructor( // endregion // region Message parsers - private fun getBodyMessage(message: Any): Any = configuration.cryptoModule?.encryptString(toJson(message)) ?: message + private fun getBodyMessage(message: Any): Any = pubnub.cryptoModuleWithLogConfig?.encryptString(toJson(message)) ?: message private fun getParamMessage(message: Any): String = - configuration.cryptoModule?.encryptString(toJson(message))?.quoted() ?: toJson(message) + pubnub.cryptoModuleWithLogConfig?.encryptString(toJson(message))?.quoted() ?: toJson(message) private fun toJson(message: Any): String = pubnub.mapper.toJson(message) // endregion diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/pubsub/SignalEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/pubsub/SignalEndpoint.kt index d65d5a6ec1..6823e57d97 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/pubsub/SignalEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/pubsub/SignalEndpoint.kt @@ -4,10 +4,14 @@ import com.pubnub.api.PubNubError import com.pubnub.api.PubNubException import com.pubnub.api.endpoints.pubsub.Signal import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.PNPublishResult import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import retrofit2.Call import retrofit2.Response @@ -20,6 +24,8 @@ class SignalEndpoint internal constructor( override val message: Any, override val customMessageType: String? = null ) : EndpointCore, PNPublishResult>(pubnub), Signal { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + companion object { private const val CUSTOM_MESSAGE_TYPE_QUERY_PARAM = "custom_message_type" } @@ -34,6 +40,20 @@ class SignalEndpoint internal constructor( override fun getAffectedChannels() = listOf(channel) override fun doWork(queryParams: HashMap): Call> { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "channel" to channel, + "message" to message, + "customMessageType" to (customMessageType ?: ""), + "queryParams" to queryParams + ) + ), + details = "Signal API call", + ) + ) + customMessageType?.let { customMessageTypeNotNull -> queryParams[CUSTOM_MESSAGE_TYPE_QUERY_PARAM] = customMessageTypeNotNull } diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/pubsub/SubscribeEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/pubsub/SubscribeEndpoint.kt index 9e779eccb6..c50d5176ad 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/pubsub/SubscribeEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/pubsub/SubscribeEndpoint.kt @@ -3,16 +3,22 @@ package com.pubnub.internal.endpoints.pubsub import com.pubnub.api.PubNubError import com.pubnub.api.PubNubException import com.pubnub.api.enums.PNOperationType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl import com.pubnub.internal.PubNubUtil +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.models.server.SubscribeEnvelope import com.pubnub.internal.toCsv import retrofit2.Call import retrofit2.Response class SubscribeEndpoint internal constructor(pubnub: PubNubImpl) : EndpointCore(pubnub) { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + var channels = emptyList() var channelGroups = emptyList() var timetoken: Long? = null @@ -32,6 +38,23 @@ class SubscribeEndpoint internal constructor(pubnub: PubNubImpl) : EndpointCore< override fun getAffectedChannelGroups() = channelGroups override fun doWork(queryParams: HashMap): Call { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "channels" to channels, + "channelGroups" to channelGroups, + "timetoken" to (timetoken ?: 0L), + "region" to (region ?: ""), + "state" to (state ?: ""), + "filterExpression" to (filterExpression ?: ""), + "queryParams" to queryParams + ) + ), + details = "Subscribe API call", + ) + ) + addQueryParams(queryParams) return retrofitManager.subscribeService.subscribe( diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/push/AddChannelsToPushEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/push/AddChannelsToPushEndpoint.kt index f5eb81182f..baf8d31551 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/push/AddChannelsToPushEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/push/AddChannelsToPushEndpoint.kt @@ -6,10 +6,14 @@ import com.pubnub.api.endpoints.push.AddChannelsToPush import com.pubnub.api.enums.PNOperationType import com.pubnub.api.enums.PNPushEnvironment import com.pubnub.api.enums.PNPushType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.push.PNPushAddChannelResult import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.toCsv import retrofit2.Call import retrofit2.Response @@ -26,6 +30,8 @@ class AddChannelsToPushEndpoint internal constructor( override val topic: String? = null, override val environment: PNPushEnvironment = PNPushEnvironment.DEVELOPMENT, ) : EndpointCore(pubnub), AddChannelsToPush { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun getAffectedChannels() = channels override fun validateParams() { @@ -42,6 +48,22 @@ class AddChannelsToPushEndpoint internal constructor( } override fun doWork(queryParams: HashMap): Call { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "pushType" to pushType, + "channels" to channels, + "deviceId" to deviceId, + "topic" to (topic ?: ""), + "environment" to environment, + "queryParams" to queryParams + ) + ), + details = "AddChannelsToPush API call", + ) + ) + addQueryParams(queryParams) return if (pushType != PNPushType.APNS2) { diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/push/ListPushProvisionsEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/push/ListPushProvisionsEndpoint.kt index 9033f4279a..3f46e889b4 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/push/ListPushProvisionsEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/push/ListPushProvisionsEndpoint.kt @@ -6,10 +6,14 @@ import com.pubnub.api.endpoints.push.ListPushProvisions import com.pubnub.api.enums.PNOperationType import com.pubnub.api.enums.PNPushEnvironment import com.pubnub.api.enums.PNPushType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.push.PNPushListProvisionsResult import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import retrofit2.Call import retrofit2.Response import java.util.Locale @@ -24,6 +28,8 @@ class ListPushProvisionsEndpoint internal constructor( override val topic: String? = null, override val environment: PNPushEnvironment = PNPushEnvironment.DEVELOPMENT, ) : EndpointCore, PNPushListProvisionsResult>(pubnub), ListPushProvisions { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun validateParams() { super.validateParams() if (deviceId.isBlank()) { @@ -35,6 +41,21 @@ class ListPushProvisionsEndpoint internal constructor( } override fun doWork(queryParams: HashMap): Call> { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "pushType" to pushType, + "deviceId" to deviceId, + "topic" to (topic ?: ""), + "environment" to environment, + "queryParams" to queryParams + ) + ), + details = "ListPushProvisions API call", + ) + ) + addQueryParams(queryParams) return if (pushType != PNPushType.APNS2) { diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/push/RemoveAllPushChannelsForDeviceEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/push/RemoveAllPushChannelsForDeviceEndpoint.kt index 74bad7ee74..b15cd67b3d 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/push/RemoveAllPushChannelsForDeviceEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/push/RemoveAllPushChannelsForDeviceEndpoint.kt @@ -6,10 +6,14 @@ import com.pubnub.api.endpoints.push.RemoveAllPushChannelsForDevice import com.pubnub.api.enums.PNOperationType import com.pubnub.api.enums.PNPushEnvironment import com.pubnub.api.enums.PNPushType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.push.PNPushRemoveAllChannelsResult import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import retrofit2.Call import retrofit2.Response import java.util.Locale @@ -24,6 +28,8 @@ class RemoveAllPushChannelsForDeviceEndpoint internal constructor( override val environment: PNPushEnvironment = PNPushEnvironment.DEVELOPMENT, override val topic: String? = null, ) : EndpointCore(pubnub), RemoveAllPushChannelsForDevice { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun validateParams() { super.validateParams() if (deviceId.isBlank()) { @@ -35,6 +41,21 @@ class RemoveAllPushChannelsForDeviceEndpoint internal constructor( } override fun doWork(queryParams: HashMap): Call { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "pushType" to pushType, + "deviceId" to deviceId, + "environment" to environment, + "topic" to (topic ?: ""), + "queryParams" to queryParams + ) + ), + details = "RemoveAllPushChannelsForDevice API call", + ) + ) + addQueryParams(queryParams) return if (pushType != PNPushType.APNS2) { diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/push/RemoveChannelsFromPushEndpoint.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/push/RemoveChannelsFromPushEndpoint.kt index 5f4dbe477e..9fe3a0b56d 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/push/RemoveChannelsFromPushEndpoint.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/endpoints/push/RemoveChannelsFromPushEndpoint.kt @@ -6,10 +6,14 @@ import com.pubnub.api.endpoints.push.RemoveChannelsFromPush import com.pubnub.api.enums.PNOperationType import com.pubnub.api.enums.PNPushEnvironment import com.pubnub.api.enums.PNPushType +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.push.PNPushRemoveChannelResult import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.toCsv import retrofit2.Call import retrofit2.Response @@ -26,6 +30,8 @@ class RemoveChannelsFromPushEndpoint internal constructor( override val topic: String? = null, override val environment: PNPushEnvironment = PNPushEnvironment.DEVELOPMENT, ) : EndpointCore(pubnub), RemoveChannelsFromPush { + private val log: PNLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + override fun getAffectedChannels() = channels override fun validateParams() { @@ -42,6 +48,22 @@ class RemoveChannelsFromPushEndpoint internal constructor( } override fun doWork(queryParams: HashMap): Call { + log.trace( + LogMessage( + message = LogMessageContent.Object( + message = mapOf( + "pushType" to pushType, + "channels" to channels, + "deviceId" to deviceId, + "topic" to (topic ?: ""), + "environment" to environment, + "queryParams" to queryParams + ) + ), + details = "RemoveChannelsFromPush API call", + ) + ) + addQueryParams(queryParams) return if (pushType != PNPushType.APNS2) { diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/eventengine/EffectDispatcher.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/eventengine/EffectDispatcher.kt index 4bae3d469f..8fc14a284c 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/eventengine/EffectDispatcher.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/eventengine/EffectDispatcher.kt @@ -1,6 +1,9 @@ package com.pubnub.internal.eventengine -import org.slf4j.LoggerFactory +import com.pubnub.api.logging.LogConfig +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent +import com.pubnub.internal.logging.LoggerManager import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ExecutorService import java.util.concurrent.Executors @@ -8,10 +11,11 @@ import java.util.concurrent.Executors internal class EffectDispatcher( private val effectFactory: EffectFactory, private val effectSource: Source, + private val logConfig: LogConfig, private val managedEffects: ConcurrentHashMap = ConcurrentHashMap(), - private val executorService: ExecutorService = Executors.newSingleThreadExecutor(), + private val executorService: ExecutorService = Executors.newSingleThreadExecutor() ) { - private val log = LoggerFactory.getLogger(EffectDispatcher::class.java) + private val log = LoggerManager.instance.getLogger(logConfig, this::class.java) fun start() { executorService.submit { @@ -31,7 +35,8 @@ internal class EffectDispatcher( } internal fun dispatch(effectInvocation: T) { - log.trace("Dispatching effect: $effectInvocation") + log.trace(LogMessage(message = LogMessageContent.Text("Dispatching effect: $effectInvocation"))) + when (val type = effectInvocation.type) { is Cancel -> { managedEffects.remove(type.idToCancel)?.cancel() diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/eventengine/EventEngine.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/eventengine/EventEngine.kt index 715671282c..eea0fc90c1 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/eventengine/EventEngine.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/eventengine/EventEngine.kt @@ -1,6 +1,9 @@ package com.pubnub.internal.eventengine -import org.slf4j.LoggerFactory +import com.pubnub.api.logging.LogConfig +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent +import com.pubnub.internal.logging.LoggerManager import java.util.concurrent.ExecutorService import java.util.concurrent.Executors @@ -8,9 +11,10 @@ internal class EventEngine, private val eventSource: Source, private var currentState: S, + private val logConfig: LogConfig, private val executorService: ExecutorService = Executors.newSingleThreadExecutor(), ) { - private val log = LoggerFactory.getLogger(EventEngine::class.java) + private val log = LoggerManager.instance.getLogger(logConfig, this::class.java) fun start() { executorService.submit { @@ -31,11 +35,24 @@ internal class EventEngine effectSink.add(invocation) } } diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/eventengine/State.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/eventengine/State.kt index 17914311bf..55afe1d45a 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/eventengine/State.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/eventengine/State.kt @@ -1,12 +1,6 @@ package com.pubnub.internal.eventengine -import org.slf4j.LoggerFactory - internal interface State> { - companion object { - internal val logger = LoggerFactory.getLogger(this::class.java) - } - fun onEntry(): Set = setOf() fun onExit(): Set = setOf() @@ -20,11 +14,6 @@ internal fun > S.transit state: S, vararg invocations: Ei, ): Pair> { - State.logger.trace( - "Transitioning from ${this::class.simpleName} to ${state::class.simpleName} with ${invocations.size} " + - "invocations: ${invocations.joinToString(", ")}", - ) - val effectInvocations = this.onExit() + invocations + state.onEntry() return Pair(state, effectInvocations) } diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/extension/JsonElement.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/extension/JsonElement.kt index 22f1b7c1bc..b5479abab2 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/extension/JsonElement.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/extension/JsonElement.kt @@ -3,20 +3,20 @@ package com.pubnub.internal.extension import com.google.gson.JsonElement import com.pubnub.api.PubNubError import com.pubnub.api.crypto.CryptoModule +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.internal.crypto.decryptString +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.managers.MapperManager -import org.slf4j.LoggerFactory - -private val log = LoggerFactory.getLogger("JsonElement") private const val PN_OTHER = "pn_other" internal fun JsonElement.tryDecryptMessage( cryptoModule: CryptoModule?, mapper: MapperManager, + logger: PNLogger, ): Pair { cryptoModule ?: return this to null - val inputText = if (mapper.isJsonObject(this)) { // property pn_other is used when we want to send encrypted Push Notification, not whole JSON object is encrypted but only value of pn_other property @@ -25,21 +25,21 @@ internal fun JsonElement.tryDecryptMessage( mapper.elementToString(this, PN_OTHER) } else { // plain JSON object indicates that this is not encrypted message - return this to logAndReturnDecryptionError() + return this to logAndReturnDecryptionError(logger) } } else if (isJsonPrimitive && asJsonPrimitive.isString) { // String may represent not encrypted string or encrypted data. We will check this when decrypting. mapper.elementToString(this) } else { // Input represents some other Json structure, such as JsonArray - return this to logAndReturnDecryptionError() + return this to logAndReturnDecryptionError(logger) } val outputText = try { cryptoModule.decryptString(inputText!!) } catch (e: Exception) { - return this to logAndReturnDecryptionError() + return this to logAndReturnDecryptionError(logger) } var outputObject = mapper.fromJson(outputText, JsonElement::class.java) @@ -53,8 +53,13 @@ internal fun JsonElement.tryDecryptMessage( return outputObject to null } -private fun logAndReturnDecryptionError(): PubNubError { +private fun logAndReturnDecryptionError(logger: PNLogger): PubNubError { val pnError = PubNubError.CRYPTO_IS_CONFIGURED_BUT_MESSAGE_IS_NOT_ENCRYPTED - log.warn(pnError.message) + logger.warn( + LogMessage( + message = LogMessageContent.Text(pnError.message), + location = "JsonElement.tryDecryptMessage", + ) + ) return pnError } diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/logging/CompositeLogger.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/logging/CompositeLogger.kt new file mode 100644 index 0000000000..801476c5bf --- /dev/null +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/logging/CompositeLogger.kt @@ -0,0 +1,168 @@ +package com.pubnub.internal.logging + +import com.pubnub.api.logging.CustomLogger +import com.pubnub.api.logging.ErrorDetails +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent +import com.pubnub.api.logging.LogMessageType +import com.pubnub.internal.logging.networkLogging.simplified +import org.slf4j.Logger +import org.slf4j.event.Level + +/** + * Composite logger that delegates to multiple loggers. + * Ensures all loggers receive the same messages. + */ +class CompositeLogger( + private val slf4jLogger: Logger, + private val location: String, + private val pnInstanceId: String, + private val toPortalLogger: PNLogger? = null, + private val customLoggers: List? = null, +) : PNLogger { + override fun trace(message: LogMessage) { + val enhancedLogMessage = LogMessage( + message = message.message, + details = message.details, + type = message.type, + location = message.location ?: location, + pubNubId = pnInstanceId, + logLevel = Level.TRACE, + timestamp = message.timestamp + ) + slf4jLogger.trace(enhancedLogMessage.simplified()) + toPortalLogger?.trace(enhancedLogMessage) + delegateToCustomLoggers { logger: CustomLogger -> + sendMessageToCustomLogger(logger, enhancedLogMessage) + } + } + + override fun debug(message: LogMessage) { + val enhancedLogMessage = LogMessage( + message = message.message, + details = message.details, + type = message.type, + location = message.location ?: location, + pubNubId = pnInstanceId, + logLevel = Level.DEBUG, + timestamp = message.timestamp + ) + slf4jLogger.debug(enhancedLogMessage.simplified()) + toPortalLogger?.debug(enhancedLogMessage) + delegateToCustomLoggers { logger: CustomLogger -> + sendMessageToCustomLogger(logger, enhancedLogMessage) + } + } + + override fun info(message: LogMessage) { + val enhancedLogMessage = LogMessage( + message = message.message, + details = message.details, + type = message.type, + location = message.location ?: location, + pubNubId = pnInstanceId, + logLevel = Level.INFO, + timestamp = message.timestamp + ) + slf4jLogger.info(enhancedLogMessage.simplified()) + toPortalLogger?.info(enhancedLogMessage) + delegateToCustomLoggers { logger: CustomLogger -> + sendMessageToCustomLogger(logger, enhancedLogMessage) + } + } + + override fun warn(message: LogMessage) { + val enhancedLogMessage = LogMessage( + message = message.message, + details = message.details, + type = message.type, + location = message.location ?: location, + pubNubId = pnInstanceId, + logLevel = Level.WARN, + timestamp = message.timestamp + ) + slf4jLogger.warn(enhancedLogMessage.simplified()) + toPortalLogger?.warn(enhancedLogMessage) + delegateToCustomLoggers { logger: CustomLogger -> + sendMessageToCustomLogger(logger, enhancedLogMessage) + } + } + + override fun error(message: LogMessage) { + val enhancedLogMessage = LogMessage( + message = message.message, + details = message.details, + type = message.type, + location = message.location ?: location, + pubNubId = pnInstanceId, + logLevel = Level.ERROR, + timestamp = message.timestamp + ) + slf4jLogger.error(enhancedLogMessage.simplified()) + toPortalLogger?.error(enhancedLogMessage) + delegateToCustomLoggers { logger: CustomLogger -> + sendMessageToCustomLogger(logger, enhancedLogMessage) + } + } + + private fun sendMessageToCustomLogger(logger: CustomLogger, message: LogMessage) { + when (message.logLevel) { + Level.TRACE -> { + logger.trace(logMessage = message) + logger.trace(message = message.simplified()) + } + + Level.DEBUG -> { + logger.debug(logMessage = message) + logger.debug(message = message.simplified()) + } + + Level.INFO -> { + logger.info(logMessage = message) + logger.info(message = message.simplified()) + } + + Level.WARN -> { + logger.warn(logMessage = message) + logger.warn(message = message.simplified()) + } + + Level.ERROR -> { + logger.error(logMessage = message) + logger.error(message = message.simplified()) + } + + else -> throw IllegalArgumentException("Unsupported log level: ${message.logLevel}") + } + } + + private inline fun delegateToCustomLoggers(action: (CustomLogger) -> Unit) { + customLoggers?.forEach { logger -> + try { + action(logger) + } catch (e: Exception) { + // Log through primary logger if custom logger fails + // but don't let it crash the logging system + try { + val logMessage = LogMessage( + message = LogMessageContent.Error( + ErrorDetails( + type = this::class.java.simpleName, + message = "Custom logger ${logger.name} failed: ${e.message}", + ) + ), + type = LogMessageType.ERROR, + location = "CompositeLogger", + pubNubId = pnInstanceId, + logLevel = Level.ERROR + ) + slf4jLogger.error(logMessage.simplified()) + toPortalLogger?.error(logMessage) + } catch (ignored: Exception) { + // If even primary logger fails, there's nothing more we can do + // Don't let logging crash the application + } + } + } + } +} diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/logging/ConfigurationLogger.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/logging/ConfigurationLogger.kt new file mode 100644 index 0000000000..da239dedd5 --- /dev/null +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/logging/ConfigurationLogger.kt @@ -0,0 +1,99 @@ +package com.pubnub.internal.logging + +import com.pubnub.api.enums.PNLogVerbosity +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent +import com.pubnub.api.v2.PNConfiguration + +private const val NOT_SET = "not set" + +object ConfigurationLogger { + fun logConfiguration( + configuration: PNConfiguration, + logger: PNLogger, + instanceId: String, + className: Class<*> + ) { + val configSummary = mapOf( + // Required parameters + "userId" to configuration.userId.value, + "subscribeKey" to configuration.subscribeKey, + // Optional parameters + "publishKey" to (configuration.publishKey.takeIf { it.isNotBlank() } ?: NOT_SET), + "secretKey" to (configuration.secretKey.takeIf { it.isNotBlank() }?.let { "set: *****" } ?: NOT_SET), + // Security and connection settings + "secure" to configuration.secure, + "origin" to (configuration.origin.takeIf { it.isNotBlank() } ?: "default"), + "logVerbosity" to (configuration.logVerbosity.takeIf { it == PNLogVerbosity.BODY }?.let { "(Deprecated) ${it.name}" } ?: NOT_SET), + "cacheBusting" to configuration.cacheBusting, + // Timeout configurations + "connectTimeout" to configuration.connectTimeout, + "subscribeTimeout" to configuration.subscribeTimeout, + "nonSubscribeReadTimeout" to configuration.nonSubscribeReadTimeout, + // Presence and heartbeat settings + "presenceTimeout" to configuration.presenceTimeout, + "heartbeatInterval" to configuration.heartbeatInterval, + "heartbeatNotificationOptions" to configuration.heartbeatNotificationOptions.name, + "suppressLeaveEvents" to configuration.suppressLeaveEvents, + "maintainPresenceState" to configuration.maintainPresenceState, + // Authentication + "authKey" to (configuration.authKey.takeIf { it.isNotBlank() }?.let { "(@Deprecated) set: *****" } ?: NOT_SET), + "authToken" to (configuration.authToken?.takeIf { it.isNotBlank() }?.let { "set: *****" } ?: NOT_SET), + // Filtering and subscriptions + "filterExpression" to (configuration.filterExpression.takeIf { it.isNotBlank() } ?: NOT_SET), + "dedupOnSubscribe" to configuration.dedupOnSubscribe, + "maximumMessagesCacheSize" to configuration.maximumMessagesCacheSize, + // Retry and reliability + "retryConfiguration" to (configuration.retryConfiguration.javaClass.simpleName ?: "none"), + "fileMessagePublishRetryLimit" to configuration.fileMessagePublishRetryLimit, + // Identification and tracking + "includeInstanceIdentifier" to configuration.includeInstanceIdentifier, + "includeRequestIdentifier" to configuration.includeRequestIdentifier, + "pnsdkSuffixes" to (configuration.pnsdkSuffixes.takeIf { it.isNotEmpty() } ?: NOT_SET), + // Crypto and encryption + "cryptoModule" to ( + if (configuration.cryptoModule != null) { + "enabled" + } else { + "disabled" + } + ), + // Manual presence management + "managePresenceListManually" to (configuration.managePresenceListManually ?: NOT_SET), + // Logging configuration + "customLoggers" to ( + configuration.customLoggers?.let { + "enabled (${it.size} logger${if (it.size != 1) { + "s" + } else { + "" + }})" + } ?: NOT_SET + ), + // Network and proxy settings + "proxy" to (configuration.proxy?.toString() ?: NOT_SET), + "proxySelector" to (configuration.proxySelector?.toString() ?: NOT_SET), + "proxyAuthenticator" to (configuration.proxyAuthenticator?.toString() ?: NOT_SET), + "maximumConnections" to (configuration.maximumConnections?.toString() ?: NOT_SET), + "httpLoggingInterceptor" to (configuration.httpLoggingInterceptor?.let { "(@Deprecated) enabled (${it.level})" } ?: NOT_SET), + // SSL/TLS settings + "sslSocketFactory" to (configuration.sslSocketFactory?.toString() ?: NOT_SET), + "x509ExtendedTrustManager" to (configuration.x509ExtendedTrustManager?.toString() ?: NOT_SET), + "connectionSpec" to (configuration.connectionSpec?.toString() ?: NOT_SET), + "hostnameVerifier" to (configuration.hostnameVerifier?.toString() ?: NOT_SET), + "certificatePinner" to (configuration.certificatePinner?.toString() ?: NOT_SET), + // App Engine settings + "googleAppEngineNetworking" to configuration.googleAppEngineNetworking, + // Instance identification + "instanceId" to instanceId + ) + + logger.debug( + LogMessage( + message = LogMessageContent.Object(message = configSummary), + details = "Configuration logged", + location = className.toString(), + ) + ) + } +} diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/logging/LogConfigFromPortal.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/logging/LogConfigFromPortal.kt new file mode 100644 index 0000000000..e7d607cc4b --- /dev/null +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/logging/LogConfigFromPortal.kt @@ -0,0 +1,13 @@ +package com.pubnub.internal.logging + +import org.slf4j.event.Level + +/** + * Immutable configuration loaded from portal for logging behavior. + * Thread-safe value object that represents portal-side logging configuration. + * + * @param isLoggingEnabled Whether logging to portal is enabled + * @param logLevel The minimum log level to send to portal + * @param userId The user ID for which logging is enabled + */ +class LogConfigFromPortal(val isLoggingEnabled: Boolean, val logLevel: Level, val userId: String) diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/logging/LoggerManager.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/logging/LoggerManager.kt new file mode 100644 index 0000000000..eb439c0e84 --- /dev/null +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/logging/LoggerManager.kt @@ -0,0 +1,88 @@ +package com.pubnub.internal.logging + +import com.pubnub.api.logging.LogConfig +import org.slf4j.Logger + +/** + * Manages logger creation with dependency injection support for better testability. + * Ensures logging never fails the application by providing fallback mechanisms. + * + * This class is fully thread-safe and can be used concurrently from multiple threads + */ +class LoggerManager( + private val loggerFactory: (Class<*>) -> Logger = { org.slf4j.LoggerFactory.getLogger(it) }, +) { + /** + * Creates a logger for the given configuration and class. + * Returns a fallback logger if creation fails to prevent application crashes. + */ + fun getLogger(logConfig: LogConfig, clazz: Class<*>): PNLogger { + return try { + createLogger(logConfig, clazz) + } catch (e: Exception) { + // Return fallback logger if creation fails + createFallbackLogger(clazz, e) + } + } + + private fun createLogger(logConfig: LogConfig, clazz: Class<*>): PNLogger { + val slf4jLogger: Logger = loggerFactory(clazz) +// val toPortalLogger = ToPortalLogger(userId = logConfig.userId) // todo enable when ready + return CompositeLogger( + slf4jLogger, + clazz.simpleName, + logConfig.pnInstanceId, + null, + logConfig.customLoggers + ) + } + + private fun createFallbackLogger(clazz: Class<*>, cause: Exception): PNLogger { + // Try to create a basic SLF4J logger as fallback + return try { + val fallbackSlf4jLogger = org.slf4j.LoggerFactory.getLogger(clazz) + fallbackSlf4jLogger.warn("Failed to create portal logger. Using fallback", cause) + + // Create a minimal logger + CompositeLogger(fallbackSlf4jLogger, location = clazz.simpleName, pnInstanceId = "fallback-instance") + } catch (fallbackException: Exception) { + // If even SLF4J fails, return no-op logger + NoOpLogger(clazz) + } + } + + companion object { + /** + * Default instance for backwards compatibility. + */ + @JvmStatic + val instance = LoggerManager() + } +} + +/** + * No-operation logger implementation used as last resort fallback. + * Ensures logging calls never crash the application. + */ +private class NoOpLogger(private val clazz: Class<*>) : PNLogger { + override fun trace(message: com.pubnub.api.logging.LogMessage) { + // No-op + } + + override fun debug(message: com.pubnub.api.logging.LogMessage) { + // No-op + } + + override fun info(message: com.pubnub.api.logging.LogMessage) { + // No-op + } + + override fun warn(message: com.pubnub.api.logging.LogMessage) { + // No-op + } + + override fun error(message: com.pubnub.api.logging.LogMessage) { + // Emergency fallback - print to System.err only in critical cases + System.err.println("CRITICAL: Logger failure in ${clazz.simpleName}: ${message.message}") + } +} diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/logging/PNLogger.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/logging/PNLogger.kt new file mode 100644 index 0000000000..47ec743670 --- /dev/null +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/logging/PNLogger.kt @@ -0,0 +1,15 @@ +package com.pubnub.internal.logging + +import com.pubnub.api.logging.LogMessage + +interface PNLogger { + fun trace(message: LogMessage) + + fun debug(message: LogMessage) + + fun info(message: LogMessage) + + fun warn(message: LogMessage) + + fun error(message: LogMessage) +} diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/logging/ToPortalLogger.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/logging/ToPortalLogger.kt new file mode 100644 index 0000000000..f71ae6aeb6 --- /dev/null +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/logging/ToPortalLogger.kt @@ -0,0 +1,75 @@ +package com.pubnub.internal.logging + +import com.pubnub.api.logging.LogMessage +import org.slf4j.event.Level +import org.slf4j.event.Level.DEBUG +import org.slf4j.event.Level.ERROR +import org.slf4j.event.Level.INFO +import org.slf4j.event.Level.TRACE +import org.slf4j.event.Level.WARN + +/** + * Logger implementation that sends logs to a portal. + */ +class ToPortalLogger( + private val userId: String, +) : PNLogger { + override fun trace(message: LogMessage) { + onLog(TRACE, message) + } + + override fun debug(message: LogMessage) { + onLog(DEBUG, message) + } + + override fun info(message: LogMessage) { + onLog(INFO, message) + } + + override fun warn(message: LogMessage) { + onLog(WARN, message) + } + + override fun error(message: LogMessage) { + onLog(ERROR, message) + } + + private fun onLog(level: Level, message: LogMessage) { + if (isLoggingToPortalEnabled() && shouldLogMessageForThisUser() && shouldLogMessageForThisLevel(level)) { + // todo implement sending to portal + // replace message content with calculated finger print using logic from ADR both for LogMessageType.OBJECT + // that is used to log details about API calls and also in NetworkRequest, NetworkResponse + } + } + + private fun shouldLogMessageForThisLevel(level: Level): Boolean { + val configuredLevel = getConfigFromPortal().logLevel + return level.toInt() >= configuredLevel.toInt() + } + + private fun isLoggingToPortalEnabled(): Boolean { + return getConfigFromPortal().isLoggingEnabled + } + + private fun shouldLogMessageForThisUser(): Boolean { + return getConfigFromPortal().userId == userId + } + + private fun getConfigFromPortal(): LogConfigFromPortal = portalConfig + + // Thread-safe lazy configuration loading + private val portalConfig: LogConfigFromPortal by lazy { + loadConfigFromPortal() + } + + // todo when service available replace it with configu retrival from portal + private fun loadConfigFromPortal(): LogConfigFromPortal { + // This function should retrieve the logging configuration from the portal + // For now, we return a default configuration + return LogConfigFromPortal( + isLoggingEnabled = false, + logLevel = INFO, + userId = "defaultUserId" + ) + } +} diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/logging/networkLogging/CustomPnHttpLoggingInterceptor.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/logging/networkLogging/CustomPnHttpLoggingInterceptor.kt new file mode 100644 index 0000000000..63a09dbcc5 --- /dev/null +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/logging/networkLogging/CustomPnHttpLoggingInterceptor.kt @@ -0,0 +1,173 @@ +package com.pubnub.internal.logging.networkLogging + +import com.pubnub.api.enums.PNLogVerbosity +import com.pubnub.api.logging.ErrorDetails +import com.pubnub.api.logging.HttpMethod +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent +import com.pubnub.api.logging.NetworkLog +import com.pubnub.api.logging.NetworkRequestMessage +import com.pubnub.api.logging.NetworkResponseMessage +import com.pubnub.internal.logging.PNLogger +import com.pubnub.internal.managers.MapperManager +import okhttp3.Interceptor +import okhttp3.Request +import okhttp3.Response +import okhttp3.ResponseBody.Companion.toResponseBody +import java.io.IOException +import java.util.Base64 + +private const val PUBNUB_OKHTTP_LOG_TAG = "pubnub.okhttp" + +class CustomPnHttpLoggingInterceptor( + private val logger: PNLogger, + private val mapperManager: MapperManager, + private val logVerbosity: PNLogVerbosity, +) : Interceptor { + override fun intercept(chain: Interceptor.Chain): Response { + val request = chain.request() + val requestStartTime = System.currentTimeMillis() + val location = request.url.pathSegments.firstOrNull() ?: "unknown" + + // Log request + logRequest(request, location) + + var response: Response? = null + + try { + response = chain.proceed(request) + + // Log response and get the modified response with cloned body + val modifiedResponse = logResponse(response, location) + return modifiedResponse + } catch (e: Exception) { + logError(request, location, e, requestStartTime) + + throw e + } + } + + private fun logRequest(request: Request, location: String) { + val url = request.url + val origin = "${url.scheme}://${url.host}" + val path = url.encodedPath + if (url.encodedQuery != null) { + "?${url.encodedQuery}" + } else { + "" + } + + // Parse query parameters + val queryParams = url.queryParameterNames.associateWith { url.queryParameter(it) ?: "" } + + // Parse headers + val headers = request.headers.toMap() + + val networkRequest = NetworkRequestMessage( + origin = origin, + path = path, + query = queryParams.takeIf { it.isNotEmpty() }, + method = HttpMethod.fromString(request.method.lowercase()), + headers = headers.takeIf { it.isNotEmpty() }, + formData = null, // TODO: Parse form data if needed + body = request.body.toString(), + timeout = null, // TODO: Extract from request if available + ) + + val requestLog = NetworkLog.Request( + message = networkRequest, + canceled = false, + failed = false + ) + + val logMessage = LogMessage( + message = LogMessageContent.NetworkRequest(requestLog), + details = "HTTP Request", + location = location, + ) + + logger.debug(logMessage) + // to keep PNLogVerbosity.BODY functional + if (logVerbosity == PNLogVerbosity.BODY) { + val jsonMessage = mapperManager.toJson(logMessage) + println("[$PUBNUB_OKHTTP_LOG_TAG] REQUEST: $jsonMessage") + } + } + + private fun logResponse(response: Response, location: String): Response { + val url = response.request.url.toString() + val status = response.code + + // Parse headers + val headers = response.headers.toMap() + + // Parse body and create modified response with cloned body + val (body, modifiedResponse) = response.body?.let { responseBody -> + val contentType = responseBody.contentType()?.toString() ?: "" + + try { + if (contentType.contains("application/json") || contentType.startsWith("text/")) { + val bodyString = responseBody.string() + val clonedResponseBody = bodyString.toResponseBody(responseBody.contentType()) + val newResponse = response.newBuilder().body(clonedResponseBody).build() + bodyString to newResponse + } else { + val bytes = responseBody.bytes() + val clonedResponseBody = bytes.toResponseBody(responseBody.contentType()) + val newResponse = response.newBuilder().body(clonedResponseBody).build() + Base64.getEncoder().encodeToString(bytes) to newResponse + } + } catch (e: IOException) { + "[Error reading response body: ${e.message}]" to response + } + } ?: (null to response) + + val networkResponse = NetworkResponseMessage( + url = url, + status = status, + headers = headers.takeIf { it.isNotEmpty() }, + body = body + ) + + val responseLog = NetworkLog.Response(message = networkResponse) + + val logMessage = LogMessage( + message = LogMessageContent.NetworkResponse(responseLog), + details = "HTTP Response", + location = location, + ) + + logger.debug(logMessage) + // to keep PNLogVerbosity.BODY functional + if (logVerbosity == PNLogVerbosity.BODY) { + val jsonMessage = mapperManager.toJson(logMessage) + println("[$PUBNUB_OKHTTP_LOG_TAG] RESPONSE: $jsonMessage") + } + + return modifiedResponse + } + + private fun logError(request: Request, location: String, error: Exception, requestStartTime: Long) { + val duration = System.currentTimeMillis() - requestStartTime + + val errorDetails = LogMessageContent.Error( + message = ErrorDetails( + type = error.javaClass.simpleName, + message = error.message ?: "Unknown error", + stack = error.stackTrace.take(10).map { it.toString() } + ) + ) + + val logMessage = LogMessage( + message = errorDetails, + details = "HTTP Request failed after ${duration}ms: ${error.message}", + location = location, + ) + + logger.error(logMessage) + // to keep PNLogVerbosity.BODY functional + if (logVerbosity == PNLogVerbosity.BODY) { + val jsonMessage = mapperManager.toJson(logMessage) + println("[$PUBNUB_OKHTTP_LOG_TAG] ERROR: $jsonMessage") + } + } +} diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/logging/networkLogging/LogMessageFormatter.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/logging/networkLogging/LogMessageFormatter.kt new file mode 100644 index 0000000000..67e581c203 --- /dev/null +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/logging/networkLogging/LogMessageFormatter.kt @@ -0,0 +1,49 @@ +package com.pubnub.internal.logging.networkLogging + +import com.google.gson.Gson +import com.google.gson.GsonBuilder +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent + +/** + * Formatter for log messages + */ +object LogMessageFormatter { + private val prettyGson: Gson by lazy { + GsonBuilder().setPrettyPrinting().create() + } + + /** + * Formats message content based on type. + * Uses cached Gson instances for better performance. + */ + fun formatMessageContent(content: LogMessageContent): String { + return try { + when (content) { + is LogMessageContent.Text -> content.message + is LogMessageContent.Object -> prettyGson.toJson(content.message) + is LogMessageContent.Error -> { + val err = content.message + "Error(type=${err.type}, message=${err.message}, stack=${err.stack?.joinToString("\n")})" + } + is LogMessageContent.NetworkRequest -> { + "NetworkRequest:\n${prettyGson.toJson(content.message)}" + } + is LogMessageContent.NetworkResponse -> { + "NetworkResponse:\n${prettyGson.toJson(content.message)}" + } + else -> content.toString() + } + } catch (e: Exception) { + "Failed to format message content: ${e.message}" + } + } +} + +/** + * Extension function to create a simplified string representation of LogMessage. + */ +fun LogMessage.simplified(): String { + val messageContent = LogMessageFormatter.formatMessageContent(this.message) + return "pnInstanceId: $pubNubId location: $location details: ${details ?: ""}\n$messageContent" +} diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/managers/ListenerManager.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/managers/ListenerManager.kt index 7d6ee822d9..13af217f41 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/managers/ListenerManager.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/managers/ListenerManager.kt @@ -3,6 +3,8 @@ package com.pubnub.internal.managers import com.pubnub.api.PubNub import com.pubnub.api.callbacks.Listener import com.pubnub.api.callbacks.SubscribeCallback +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.PNStatus import com.pubnub.api.models.consumer.pubsub.PNEvent import com.pubnub.api.models.consumer.pubsub.PNMessageResult @@ -16,9 +18,11 @@ import com.pubnub.api.v2.callbacks.EventListener import com.pubnub.api.v2.callbacks.StatusEmitter import com.pubnub.api.v2.callbacks.StatusListener import com.pubnub.api.v2.subscriptions.Subscription +import com.pubnub.internal.PubNubImpl +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.subscribe.eventengine.effect.MessagesConsumer import com.pubnub.internal.subscribe.eventengine.effect.StatusConsumer -import org.slf4j.LoggerFactory import java.util.concurrent.CopyOnWriteArrayList class ListenerManager(val pubnub: PubNub) : MessagesConsumer, StatusConsumer, EventEmitter, StatusEmitter { @@ -27,7 +31,7 @@ class ListenerManager(val pubnub: PubNub) : MessagesConsumer, StatusConsumer, Ev private val statusListeners get() = listeners.filterIsInstance() private val eventListeners get() = listeners.filterIsInstance() - private val log = LoggerFactory.getLogger(this.javaClass.simpleName) + private val log: PNLogger = LoggerManager.instance.getLogger((pubnub as PubNubImpl).logConfig, this::class.java) /** * Add a listener. @@ -118,7 +122,7 @@ class ListenerManager(val pubnub: PubNub) : MessagesConsumer, StatusConsumer, Ev try { action(element) } catch (e: Throwable) { - log.warn("Uncaught exception in listener.", e) + log.warn(LogMessage(message = LogMessageContent.Text("Caught exception in listener: ${e.message}"))) } } } diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/managers/MapperManager.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/managers/MapperManager.kt index 69e2b9538f..352e1d41cc 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/managers/MapperManager.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/managers/MapperManager.kt @@ -19,7 +19,12 @@ import com.google.gson.stream.JsonToken import com.google.gson.stream.JsonWriter import com.pubnub.api.PubNubError import com.pubnub.api.PubNubException +import com.pubnub.api.logging.ErrorDetails +import com.pubnub.api.logging.LogConfig +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.utils.PatchValue +import com.pubnub.internal.logging.LoggerManager import org.json.JSONArray import org.json.JSONException import org.json.JSONObject @@ -28,7 +33,8 @@ import retrofit2.converter.gson.GsonConverterFactory import java.lang.reflect.ParameterizedType import java.lang.reflect.Type -class MapperManager { +class MapperManager(private val logConfig: LogConfig) { + private val log = LoggerManager.instance.getLogger(logConfig, this::class.java) private val objectMapper: Gson internal val converterFactory: Converter.Factory @@ -228,7 +234,13 @@ class MapperManager { input: JsonElement?, clazz: Class, ): T { - return this.objectMapper.fromJson(input, clazz) as T + log.debug(LogMessage(message = LogMessageContent.Text("Deserializing message content"))) + + val result = this.objectMapper.fromJson(input, clazz) as T + + log.debug(LogMessage(message = LogMessageContent.Text("Message deserialized successfully"))) + + return result } fun convertValue( @@ -239,8 +251,9 @@ class MapperManager { } fun toJson(input: Any?): String { + log.debug(LogMessage(message = LogMessageContent.Text("Serializing message content"))) try { - return if (input is List<*> && input.javaClass.isAnonymousClass) { + val result = if (input is List<*> && input.javaClass.isAnonymousClass) { objectMapper.toJson(input, List::class.java) } else if (input is Map<*, *> && input.javaClass.isAnonymousClass) { objectMapper.toJson(input, Map::class.java) @@ -249,7 +262,21 @@ class MapperManager { } else { objectMapper.toJson(input) } + + log.debug(LogMessage(message = LogMessageContent.Text("Message serialized successfully"))) + + return result } catch (e: JsonParseException) { + log.error( + LogMessage( + message = LogMessageContent.Error( + ErrorDetails( + type = e.javaClass.simpleName, + message = "Serialization of content failed due to: ${e.message}" + ) + ) + ) + ) throw PubNubException( pubnubError = PubNubError.JSON_ERROR, errorMessage = e.message, diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/managers/RetrofitManager.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/managers/RetrofitManager.kt index 43a110dcbc..a32f741d1b 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/managers/RetrofitManager.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/managers/RetrofitManager.kt @@ -1,9 +1,10 @@ package com.pubnub.internal.managers -import com.pubnub.api.enums.PNLogVerbosity import com.pubnub.api.v2.PNConfiguration import com.pubnub.internal.PubNubImpl import com.pubnub.internal.interceptor.SignatureInterceptor +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.networkLogging.CustomPnHttpLoggingInterceptor import com.pubnub.internal.services.AccessManagerService import com.pubnub.internal.services.ChannelGroupService import com.pubnub.internal.services.FilesService @@ -20,7 +21,6 @@ import com.pubnub.internal.services.TimeService import com.pubnub.internal.vendor.AppEngineFactory.Factory import okhttp3.Call import okhttp3.OkHttpClient -import okhttp3.logging.HttpLoggingInterceptor import org.jetbrains.annotations.TestOnly import org.slf4j.LoggerFactory import org.slf4j.helpers.NOPLoggerFactory @@ -28,11 +28,10 @@ import retrofit2.Retrofit import java.util.concurrent.ExecutorService import java.util.concurrent.TimeUnit -private const val PUBNUB_OKHTTP_REQUEST_RESPONSE_LOGGER_NAME = "pubnub.okhttp" - class RetrofitManager( val pubnub: PubNubImpl, private val configuration: PNConfiguration, + // todo make private @get:TestOnly internal var transactionClientInstance: OkHttpClient? = null, @get:TestOnly internal var subscriptionClientInstance: OkHttpClient? = null, @get:TestOnly internal var noSignatureClientInstance: OkHttpClient? = null, @@ -110,22 +109,17 @@ class RetrofitManager( .connectTimeout(configuration.connectTimeout.toLong(), TimeUnit.SECONDS) with(configuration) { - if (logVerbosity == PNLogVerbosity.BODY) { - okHttpBuilder.addInterceptor( - HttpLoggingInterceptor { message -> - if (slf4jIsBound()) { - // will follow whatever SLF4J config (logback, log4j2, etc.) is on the classpath - LoggerFactory.getLogger(PUBNUB_OKHTTP_REQUEST_RESPONSE_LOGGER_NAME).debug(message) - } else { - // fallback: always print - println("[$PUBNUB_OKHTTP_REQUEST_RESPONSE_LOGGER_NAME] $message") - } - }.apply { - level = HttpLoggingInterceptor.Level.BODY - } - ) + okHttpBuilder.interceptors().removeAll { interceptor -> + interceptor is CustomPnHttpLoggingInterceptor } + // todo detect that this is publish to portal and not log this to avoid recursion + // Replace the standard HttpLoggingInterceptor with our custom one + val customLogger = LoggerManager.instance.getLogger(pubnub.logConfig, this::class.java) + okHttpBuilder.addInterceptor( + CustomPnHttpLoggingInterceptor(customLogger, pubnub.mapper, logVerbosity) + ) + if (httpLoggingInterceptor != null) { okHttpBuilder.addInterceptor(httpLoggingInterceptor!!) } diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/presence/Presence.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/presence/Presence.kt index 98dd63d3e5..3ef3f3ae08 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/presence/Presence.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/presence/Presence.kt @@ -3,9 +3,13 @@ package com.pubnub.internal.presence import com.pubnub.api.PubNubException import com.pubnub.api.enums.PNHeartbeatNotificationOptions import com.pubnub.api.enums.PNStatusCategory +import com.pubnub.api.logging.LogConfig +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.PNStatus import com.pubnub.internal.eventengine.EffectDispatcher import com.pubnub.internal.eventengine.EventEngineConf +import com.pubnub.internal.logging.LoggerManager import com.pubnub.internal.managers.ListenerManager import com.pubnub.internal.managers.PresenceEventEngineManager import com.pubnub.internal.presence.eventengine.PresenceEventEngine @@ -15,7 +19,6 @@ import com.pubnub.internal.presence.eventengine.effect.PresenceEffectInvocation import com.pubnub.internal.presence.eventengine.effect.effectprovider.HeartbeatProvider import com.pubnub.internal.presence.eventengine.effect.effectprovider.LeaveProvider import com.pubnub.internal.presence.eventengine.event.PresenceEvent -import org.slf4j.LoggerFactory import java.util.concurrent.ScheduledExecutorService import kotlin.time.Duration @@ -32,6 +35,7 @@ internal interface Presence { presenceData: PresenceData = PresenceData(), sendStateWithHeartbeat: Boolean, executorService: ScheduledExecutorService, + logConfig: LogConfig, ): Presence { if (heartbeatInterval <= Duration.ZERO) { return PresenceNoOp( @@ -41,7 +45,8 @@ internal interface Presence { listenerManager, heartbeatNotificationOptions, presenceData, - sendStateWithHeartbeat + sendStateWithHeartbeat, + logConfig ) } @@ -56,17 +61,20 @@ internal interface Presence { statusConsumer = listenerManager, presenceData = presenceData, sendStateWithHeartbeat = sendStateWithHeartbeat, + logConfig = logConfig, ) val eventEngineManager = PresenceEventEngineManager( eventEngine = PresenceEventEngine( effectSink = eventEngineConf.effectSink, eventSource = eventEngineConf.eventSource, + logConfig = logConfig, ), eventSink = eventEngineConf.eventSink, effectDispatcher = EffectDispatcher( effectFactory = effectFactory, effectSource = eventEngineConf.effectSource, + logConfig = logConfig, ), ).also { it.start() } @@ -113,8 +121,9 @@ internal class PresenceNoOp( private val heartbeatNotificationOptions: PNHeartbeatNotificationOptions, private val presenceData: PresenceData, private val sendStateWithHeartbeat: Boolean, + private val logConfig: LogConfig, ) : Presence { - private val log = LoggerFactory.getLogger(PresenceNoOp::class.java) + private val log = LoggerManager.instance.getLogger(logConfig, this::class.java) private val channels = mutableSetOf() private val channelGroups = mutableSetOf() @@ -142,7 +151,12 @@ internal class PresenceNoOp( if (heartbeatNotificationOptions == PNHeartbeatNotificationOptions.ALL || heartbeatNotificationOptions == PNHeartbeatNotificationOptions.FAILURES ) { - listenerManager.announce(PNStatus(PNStatusCategory.PNHeartbeatFailed, PubNubException.from(exception))) + listenerManager.announce( + PNStatus( + PNStatusCategory.PNHeartbeatFailed, + PubNubException.from(exception) + ) + ) } }.onSuccess { if (heartbeatNotificationOptions == PNHeartbeatNotificationOptions.ALL) { @@ -161,7 +175,11 @@ internal class PresenceNoOp( if (!suppressLeaveEvents && (channels.isNotEmpty() || channelGroups.isNotEmpty())) { leaveProvider.getLeaveRemoteAction(channels, channelGroups).async { result -> result.onFailure { - log.error("LeaveEffect failed", it) + log.error( + LogMessage( + message = LogMessageContent.Text("LeaveEffect from left operation failed: $it"), + ) + ) } } } @@ -174,7 +192,11 @@ internal class PresenceNoOp( if (!suppressLeaveEvents && (channels.isNotEmpty() || channelGroups.isNotEmpty())) { leaveProvider.getLeaveRemoteAction(channels, channelGroups).async { result -> result.onFailure { - log.error("LeaveEffect failed", it) + log.error( + LogMessage( + message = LogMessageContent.Text("LeaveEffect from leftAll operation failed: $it"), + ) + ) } } } diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/presence/eventengine/PresenceEventEngine.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/presence/eventengine/PresenceEventEngine.kt index e1818d11db..e5fd344e2a 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/presence/eventengine/PresenceEventEngine.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/presence/eventengine/PresenceEventEngine.kt @@ -1,5 +1,6 @@ package com.pubnub.internal.presence.eventengine +import com.pubnub.api.logging.LogConfig import com.pubnub.internal.eventengine.EventEngine import com.pubnub.internal.eventengine.Sink import com.pubnub.internal.eventengine.Source @@ -12,5 +13,6 @@ internal typealias PresenceEventEngine = EventEngine, eventSource: Source, + logConfig: LogConfig, currentState: PresenceState = PresenceState.HeartbeatInactive, -): PresenceEventEngine = EventEngine(effectSink, eventSource, currentState) +): PresenceEventEngine = EventEngine(effectSink, eventSource, currentState, logConfig) diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/presence/eventengine/effect/HeartbeatEffect.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/presence/eventengine/effect/HeartbeatEffect.kt index 01622064bf..c7efffdd1f 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/presence/eventengine/effect/HeartbeatEffect.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/presence/eventengine/effect/HeartbeatEffect.kt @@ -4,23 +4,27 @@ import com.pubnub.api.PubNubException import com.pubnub.api.endpoints.remoteaction.RemoteAction import com.pubnub.api.enums.PNHeartbeatNotificationOptions import com.pubnub.api.enums.PNStatusCategory +import com.pubnub.api.logging.LogConfig +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.PNStatus import com.pubnub.internal.eventengine.Effect import com.pubnub.internal.eventengine.Sink +import com.pubnub.internal.logging.LoggerManager import com.pubnub.internal.presence.eventengine.event.PresenceEvent import com.pubnub.internal.subscribe.eventengine.effect.StatusConsumer -import org.slf4j.LoggerFactory internal class HeartbeatEffect( val heartbeatRemoteAction: RemoteAction, val presenceEventSink: Sink, val heartbeatNotificationOptions: PNHeartbeatNotificationOptions, val statusConsumer: StatusConsumer, + private val logConfig: LogConfig, ) : Effect { - private val log = LoggerFactory.getLogger(HeartbeatEffect::class.java) + private val log = LoggerManager.instance.getLogger(logConfig, this::class.java) override fun runEffect() { - log.trace("Running HeartbeatEffect") + log.trace(LogMessage(message = LogMessageContent.Text("Running HeartbeatEffect"))) heartbeatRemoteAction.async { result -> result.onFailure { exception -> if (heartbeatNotificationOptions == PNHeartbeatNotificationOptions.ALL || diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/presence/eventengine/effect/LeaveEffect.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/presence/eventengine/effect/LeaveEffect.kt index 9c738c94df..9f95d498f2 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/presence/eventengine/effect/LeaveEffect.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/presence/eventengine/effect/LeaveEffect.kt @@ -1,19 +1,22 @@ package com.pubnub.internal.presence.eventengine.effect import com.pubnub.api.endpoints.remoteaction.RemoteAction +import com.pubnub.api.logging.LogConfig +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.internal.eventengine.Effect -import org.slf4j.LoggerFactory +import com.pubnub.internal.logging.LoggerManager internal class LeaveEffect( val leaveRemoteAction: RemoteAction, + private val logConfig: LogConfig, ) : Effect { - private val log = LoggerFactory.getLogger(LeaveEffect::class.java) + private val log = LoggerManager.instance.getLogger(logConfig, this::class.java) override fun runEffect() { - log.trace("Running LeaveEffect") + log.trace(LogMessage(message = LogMessageContent.Text("Running LeaveEffect."))) leaveRemoteAction.async { result -> result.onFailure { - log.error("LeaveEffect failed", it) } } } diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/presence/eventengine/effect/PresenceEffectFactory.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/presence/eventengine/effect/PresenceEffectFactory.kt index 46ce65cc55..496c320fbe 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/presence/eventengine/effect/PresenceEffectFactory.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/presence/eventengine/effect/PresenceEffectFactory.kt @@ -1,6 +1,7 @@ package com.pubnub.internal.presence.eventengine.effect import com.pubnub.api.enums.PNHeartbeatNotificationOptions +import com.pubnub.api.logging.LogConfig import com.pubnub.internal.eventengine.Effect import com.pubnub.internal.eventengine.EffectFactory import com.pubnub.internal.eventengine.Sink @@ -23,6 +24,7 @@ internal class PresenceEffectFactory( private val statusConsumer: StatusConsumer, private val presenceData: PresenceData, private val sendStateWithHeartbeat: Boolean, + private val logConfig: LogConfig, ) : EffectFactory { override fun create(effectInvocation: PresenceEffectInvocation): Effect? { return when (effectInvocation) { @@ -37,7 +39,13 @@ internal class PresenceEffectFactory( null }, ) - HeartbeatEffect(heartbeatRemoteAction, presenceEventSink, heartbeatNotificationOptions, statusConsumer) + HeartbeatEffect( + heartbeatRemoteAction, + presenceEventSink, + heartbeatNotificationOptions, + statusConsumer, + logConfig + ) } is PresenceEffectInvocation.Leave -> { @@ -47,14 +55,14 @@ internal class PresenceEffectFactory( effectInvocation.channels, effectInvocation.channelGroups, ) - LeaveEffect(leaveRemoteAction) + LeaveEffect(leaveRemoteAction, logConfig) } else { null } } is PresenceEffectInvocation.Wait -> { - WaitEffect(heartbeatInterval, presenceEventSink, executorService) + WaitEffect(heartbeatInterval, presenceEventSink, executorService, logConfig) } PresenceEffectInvocation.CancelWait, diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/presence/eventengine/effect/WaitEffect.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/presence/eventengine/effect/WaitEffect.kt index e0c859fc33..91caa1efe1 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/presence/eventengine/effect/WaitEffect.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/presence/eventengine/effect/WaitEffect.kt @@ -1,10 +1,13 @@ package com.pubnub.internal.presence.eventengine.effect +import com.pubnub.api.logging.LogConfig +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.internal.eventengine.ManagedEffect import com.pubnub.internal.eventengine.Sink import com.pubnub.internal.extension.scheduleWithDelay +import com.pubnub.internal.logging.LoggerManager import com.pubnub.internal.presence.eventengine.event.PresenceEvent -import org.slf4j.LoggerFactory import java.util.concurrent.RejectedExecutionException import java.util.concurrent.ScheduledExecutorService import java.util.concurrent.ScheduledFuture @@ -14,8 +17,9 @@ internal class WaitEffect( private val heartbeatInterval: Duration, private val presenceEventSink: Sink, private val executorService: ScheduledExecutorService, + private val logConfig: LogConfig, ) : ManagedEffect { - private val log = LoggerFactory.getLogger(WaitEffect::class.java) + private val log = LoggerManager.instance.getLogger(logConfig, this::class.java) @Transient private var cancelled: Boolean = false @@ -25,7 +29,11 @@ internal class WaitEffect( @Synchronized override fun runEffect() { - log.trace("Running WaitEffect") + log.trace( + LogMessage( + message = LogMessageContent.Text("Running WaitEffect."), + ) + ) if (cancelled) { return } @@ -36,7 +44,11 @@ internal class WaitEffect( presenceEventSink.add(PresenceEvent.TimesUp) } } catch (_: RejectedExecutionException) { - log.trace("Unable to schedule retry, PubNub was likely already destroyed.") + log.trace( + LogMessage( + message = LogMessageContent.Text("Unable to schedule retry, PubNub was likely already destroyed."), + ) + ) } } diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/retry/RetryableCallback.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/retry/RetryableCallback.kt index 19f8a6d69f..f700efa175 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/retry/RetryableCallback.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/retry/RetryableCallback.kt @@ -1,9 +1,12 @@ package com.pubnub.internal.retry +import com.pubnub.api.logging.LogConfig +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.retry.RetryConfiguration import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.extension.scheduleWithDelay -import org.slf4j.LoggerFactory +import com.pubnub.internal.logging.LoggerManager import retrofit2.Call import retrofit2.Callback import retrofit2.Response @@ -18,8 +21,9 @@ internal abstract class RetryableCallback( private val call: Call, private val isEndpointRetryable: Boolean, private val executorService: ScheduledExecutorService, + private val logConfig: LogConfig, ) : Callback, RetryableBase(retryConfiguration, endpointGroupName) { - private val log = LoggerFactory.getLogger(this.javaClass.simpleName) + private val log = LoggerManager.instance.getLogger(logConfig, this::class.java) private var retryCount = 0 private var exponentialMultiplier = 0.0 @@ -81,14 +85,24 @@ internal abstract class RetryableCallback( retryCount++ val randomDelayInMillis: Int = random.nextInt(MAX_RANDOM_DELAY_IN_MILLIS) val effectiveDelay: Duration = delay + randomDelayInMillis.milliseconds - log.trace("Added random delay so effective retry delay is ${effectiveDelay.inWholeMilliseconds} millis") + log.trace( + LogMessage( + message = LogMessageContent.Text( + "Added random delay so effective retry delay is ${effectiveDelay.inWholeMilliseconds} millis" + ), + ) + ) // don't want to block the main thread in case of Android so using executorService try { executorService.scheduleWithDelay(effectiveDelay) { call.clone().enqueue(this) } } catch (_: RejectedExecutionException) { - log.trace("Unable to schedule retry, PubNub was likely already destroyed.") + log.trace( + LogMessage( + message = LogMessageContent.Text("Unable to schedule retry, PubNub was likely already destroyed."), + ) + ) } } diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/retry/RetryableRestCaller.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/retry/RetryableRestCaller.kt index edb6046dc7..3458bd293f 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/retry/RetryableRestCaller.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/retry/RetryableRestCaller.kt @@ -2,11 +2,14 @@ package com.pubnub.internal.retry import com.pubnub.api.PubNubError import com.pubnub.api.PubNubException +import com.pubnub.api.logging.LogConfig +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.retry.RetryConfiguration import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.PubNubRetryableException +import com.pubnub.internal.logging.LoggerManager import okhttp3.ResponseBody.Companion.toResponseBody -import org.slf4j.LoggerFactory import retrofit2.Call import retrofit2.Response @@ -14,8 +17,10 @@ internal class RetryableRestCaller( retryConfiguration: RetryConfiguration, endpointGroupName: RetryableEndpointGroup, private val isEndpointRetryable: Boolean, + private val logConfig: LogConfig, ) : RetryableBase(retryConfiguration, endpointGroupName) { - private val log = LoggerFactory.getLogger(this.javaClass.simpleName) + private val log = LoggerManager.instance.getLogger(logConfig, this::class.java) + internal lateinit var call: Call internal fun execute(callToBeExecuted: Call): Response { @@ -34,7 +39,11 @@ internal class RetryableRestCaller( } val randomDelayInMillis = random.nextInt(MAX_RANDOM_DELAY_IN_MILLIS) val effectiveDelayInMillis = getDelayBasedOnResponse(response).inWholeMilliseconds + randomDelayInMillis - log.trace("Added random delay so effective retry delay is $effectiveDelayInMillis") + log.trace( + LogMessage( + message = LogMessageContent.Text("Added random delay so effective retry delay is $effectiveDelayInMillis"), + ) + ) Thread.sleep(effectiveDelayInMillis) // we want to sleep here on current thread since this is synchronous call call = call.clone() diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/subscribe/Subscribe.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/subscribe/Subscribe.kt index cd7b5c8d09..d0888d18d6 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/subscribe/Subscribe.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/subscribe/Subscribe.kt @@ -65,17 +65,20 @@ internal class Subscribe( statusConsumer = listenerManager, presenceData = presenceData, sendStateWithSubscribe = sendStateWithSubscribe, + logConfig = pubNub.logConfig ) val subscribeEventEngine = SubscribeEventEngine( effectSink = eventEnginesConf.subscribe.effectSink, eventSource = eventEnginesConf.subscribe.eventSource, + logConfig = pubNub.logConfig, ) val subscribeEffectDispatcher = EffectDispatcher( effectFactory = subscribeEffectFactory, effectSource = eventEnginesConf.subscribe.effectSource, + logConfig = pubNub.logConfig, ) val subscribeEventEngineManager = diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/subscribe/eventengine/SubscribeEventEngine.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/subscribe/eventengine/SubscribeEventEngine.kt index cf49d71932..2f7ac9b408 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/subscribe/eventengine/SubscribeEventEngine.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/subscribe/eventengine/SubscribeEventEngine.kt @@ -1,5 +1,6 @@ package com.pubnub.internal.subscribe.eventengine +import com.pubnub.api.logging.LogConfig import com.pubnub.internal.eventengine.EventEngine import com.pubnub.internal.eventengine.Sink import com.pubnub.internal.eventengine.Source @@ -12,10 +13,12 @@ internal typealias SubscribeEventEngine = EventEngine, eventSource: Source, + logConfig: LogConfig, currentState: SubscribeState = SubscribeState.Unsubscribed, ): SubscribeEventEngine = EventEngine( effectSink, eventSource, currentState, + logConfig ) diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/subscribe/eventengine/effect/EmitMessagesEffect.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/subscribe/eventengine/effect/EmitMessagesEffect.kt index 17e6881294..9637cf1850 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/subscribe/eventengine/effect/EmitMessagesEffect.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/subscribe/eventengine/effect/EmitMessagesEffect.kt @@ -1,5 +1,8 @@ package com.pubnub.internal.subscribe.eventengine.effect +import com.pubnub.api.logging.LogConfig +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.pubsub.PNEvent import com.pubnub.api.models.consumer.pubsub.PNMessageResult import com.pubnub.api.models.consumer.pubsub.PNPresenceEventResult @@ -8,16 +11,21 @@ import com.pubnub.api.models.consumer.pubsub.files.PNFileEventResult import com.pubnub.api.models.consumer.pubsub.message_actions.PNMessageActionResult import com.pubnub.api.models.consumer.pubsub.objects.PNObjectEventResult import com.pubnub.internal.eventengine.Effect -import org.slf4j.LoggerFactory +import com.pubnub.internal.logging.LoggerManager internal class EmitMessagesEffect( private val messagesConsumer: MessagesConsumer, private val messages: List, + private val logConfig: LogConfig, ) : Effect { - private val log = LoggerFactory.getLogger(EmitMessagesEffect::class.java) + private val log = LoggerManager.instance.getLogger(logConfig, this::class.java) override fun runEffect() { - log.trace("Running EmitMessagesEffect") + log.trace( + LogMessage( + message = LogMessageContent.Text("Running EmitMessagesEffect: Emitting ${messages.size} messages to consumers"), + ) + ) for (message in messages) { try { when (message) { diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/subscribe/eventengine/effect/EmitStatusEffect.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/subscribe/eventengine/effect/EmitStatusEffect.kt index c6387ba220..64a3ed8aba 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/subscribe/eventengine/effect/EmitStatusEffect.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/subscribe/eventengine/effect/EmitStatusEffect.kt @@ -1,17 +1,21 @@ package com.pubnub.internal.subscribe.eventengine.effect +import com.pubnub.api.logging.LogConfig +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.PNStatus import com.pubnub.internal.eventengine.Effect -import org.slf4j.LoggerFactory +import com.pubnub.internal.logging.LoggerManager internal class EmitStatusEffect( private val statusConsumer: StatusConsumer, private val status: PNStatus, + private val logConfig: LogConfig ) : Effect { - private val log = LoggerFactory.getLogger(EmitStatusEffect::class.java) + private val log = LoggerManager.instance.getLogger(logConfig, this::class.java) override fun runEffect() { - log.trace("Running EmitStatusEffect: $status") + log.trace(LogMessage(message = LogMessageContent.Text("Running EmitStatusEffect: $status"))) statusConsumer.announce(status) } } diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/subscribe/eventengine/effect/HandshakeEffect.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/subscribe/eventengine/effect/HandshakeEffect.kt index 3920db49b5..512c10d50a 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/subscribe/eventengine/effect/HandshakeEffect.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/subscribe/eventengine/effect/HandshakeEffect.kt @@ -2,20 +2,24 @@ package com.pubnub.internal.subscribe.eventengine.effect import com.pubnub.api.PubNubException import com.pubnub.api.endpoints.remoteaction.RemoteAction +import com.pubnub.api.logging.LogConfig +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.internal.eventengine.ManagedEffect import com.pubnub.internal.eventengine.Sink +import com.pubnub.internal.logging.LoggerManager import com.pubnub.internal.subscribe.eventengine.event.SubscribeEvent import com.pubnub.internal.subscribe.eventengine.event.SubscriptionCursor -import org.slf4j.LoggerFactory internal class HandshakeEffect( private val handshakeRemoteAction: RemoteAction, private val subscribeEventSink: Sink, + private val logConfig: LogConfig, ) : ManagedEffect { - private val log = LoggerFactory.getLogger(HandshakeEffect::class.java) + private val log = LoggerManager.instance.getLogger(logConfig, this::class.java) override fun runEffect() { - log.trace("Running HandshakeEffect") + log.trace(LogMessage(message = LogMessageContent.Text("Running HandshakeEffect"))) handshakeRemoteAction.async { result -> result.onFailure { diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/subscribe/eventengine/effect/ReceiveMessagesEffect.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/subscribe/eventengine/effect/ReceiveMessagesEffect.kt index b4c69c408b..f542795b81 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/subscribe/eventengine/effect/ReceiveMessagesEffect.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/subscribe/eventengine/effect/ReceiveMessagesEffect.kt @@ -2,19 +2,23 @@ package com.pubnub.internal.subscribe.eventengine.effect import com.pubnub.api.PubNubException import com.pubnub.api.endpoints.remoteaction.RemoteAction +import com.pubnub.api.logging.LogConfig +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.internal.eventengine.ManagedEffect import com.pubnub.internal.eventengine.Sink +import com.pubnub.internal.logging.LoggerManager import com.pubnub.internal.subscribe.eventengine.event.SubscribeEvent -import org.slf4j.LoggerFactory internal class ReceiveMessagesEffect( private val receiveMessagesRemoteAction: RemoteAction, private val subscribeEventSink: Sink, + private val logConfig: LogConfig, ) : ManagedEffect { - private val log = LoggerFactory.getLogger(ReceiveMessagesEffect::class.java) + private val log = LoggerManager.instance.getLogger(logConfig, this::class.java) override fun runEffect() { - log.trace("Running ReceiveMessagesEffect") + log.trace(LogMessage(message = LogMessageContent.Text("Running ReceiveMessagesEffect"))) receiveMessagesRemoteAction.async { result -> result.onFailure { diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/subscribe/eventengine/effect/SubscribeEffectFactory.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/subscribe/eventengine/effect/SubscribeEffectFactory.kt index 61575c84f4..82ab8782d8 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/subscribe/eventengine/effect/SubscribeEffectFactory.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/subscribe/eventengine/effect/SubscribeEffectFactory.kt @@ -1,6 +1,7 @@ package com.pubnub.internal.subscribe.eventengine.effect import com.pubnub.api.endpoints.remoteaction.RemoteAction +import com.pubnub.api.logging.LogConfig import com.pubnub.api.models.consumer.pubsub.PNEvent import com.pubnub.internal.eventengine.Effect import com.pubnub.internal.eventengine.EffectFactory @@ -24,15 +25,16 @@ internal class SubscribeEffectFactory( private val statusConsumer: StatusConsumer, private val presenceData: PresenceData, private val sendStateWithSubscribe: Boolean, + private val logConfig: LogConfig ) : EffectFactory { override fun create(effectInvocation: SubscribeEffectInvocation): Effect? { return when (effectInvocation) { is SubscribeEffectInvocation.EmitMessages -> { - EmitMessagesEffect(messagesConsumer, effectInvocation.messages) + EmitMessagesEffect(messagesConsumer, effectInvocation.messages, logConfig) } is SubscribeEffectInvocation.EmitStatus -> { - EmitStatusEffect(statusConsumer, effectInvocation.status) + EmitStatusEffect(statusConsumer, effectInvocation.status, logConfig) } is SubscribeEffectInvocation.Handshake -> { @@ -46,7 +48,7 @@ internal class SubscribeEffectFactory( null }, ) - HandshakeEffect(handshakeRemoteAction, subscribeEventSink) + HandshakeEffect(handshakeRemoteAction, subscribeEventSink, logConfig) } is SubscribeEffectInvocation.ReceiveMessages -> { @@ -56,7 +58,7 @@ internal class SubscribeEffectFactory( effectInvocation.channelGroups, effectInvocation.subscriptionCursor, ) - ReceiveMessagesEffect(receiveMessagesRemoteAction, subscribeEventSink) + ReceiveMessagesEffect(receiveMessagesRemoteAction, subscribeEventSink, logConfig) } SubscribeEffectInvocation.CancelHandshake, diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/v2/PNConfigurationImpl.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/v2/PNConfigurationImpl.kt index c4c135a27c..a6e976d69c 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/v2/PNConfigurationImpl.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/v2/PNConfigurationImpl.kt @@ -4,15 +4,17 @@ import com.pubnub.api.UserId import com.pubnub.api.crypto.CryptoModule import com.pubnub.api.enums.PNHeartbeatNotificationOptions import com.pubnub.api.enums.PNLogVerbosity +import com.pubnub.api.logging.CustomLogger +import com.pubnub.api.logging.LogConfig import com.pubnub.api.retry.RetryConfiguration import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.api.v2.PNConfiguration import com.pubnub.api.v2.PNConfigurationOverride +import com.pubnub.internal.crypto.CryptoModuleImpl import okhttp3.Authenticator import okhttp3.CertificatePinner import okhttp3.ConnectionSpec import okhttp3.logging.HttpLoggingInterceptor -import org.slf4j.LoggerFactory import java.net.Proxy import java.net.ProxySelector import javax.net.ssl.HostnameVerifier @@ -26,7 +28,7 @@ class PNConfigurationImpl( override val secretKey: String = "", override val authKey: String = "", override val authToken: String? = null, - override val cryptoModule: CryptoModule? = null, + override val cryptoModule: CryptoModule? = null, // don't use getter directly use getCryptoModuleWithLogConfig to be able to properly configure logging in CryptoModule override val origin: String = "", override val secure: Boolean = true, override val logVerbosity: PNLogVerbosity = PNLogVerbosity.NONE, @@ -71,6 +73,7 @@ class PNConfigurationImpl( ) ), override val managePresenceListManually: Boolean = false, + override val customLoggers: List? = null, ) : PNConfiguration, PNConfigurationOverride { companion object { const val DEFAULT_DEDUPE_SIZE = 100 @@ -81,13 +84,26 @@ class PNConfigurationImpl( const val CONNECT_TIMEOUT = 5 } + fun getCryptoModuleWithLogConfig(logConfig: LogConfig): CryptoModule? { + return cryptoModule?.let { module -> + if (module is CryptoModuleImpl) { + CryptoModuleImpl( + primaryCryptor = module.primaryCryptor, + cryptorsForDecryptionOnly = module.cryptorsForDecryptionOnly, + logConfig = logConfig + ) + } else { + // For custom implementations, return the original instance + module + } + } + } + class Builder(defaultConfiguration: PNConfiguration) : PNConfiguration.Builder, PNConfigurationOverride.Builder { constructor(userId: UserId, subscribeKey: String) : this(PNConfigurationImpl(userId, subscribeKey)) - private val log = LoggerFactory.getLogger(this::class.simpleName) - override var userId: UserId = defaultConfiguration.userId override var subscribeKey: String = defaultConfiguration.subscribeKey @@ -106,6 +122,15 @@ class PNConfigurationImpl( override var secure: Boolean = defaultConfiguration.secure + @Deprecated( + message = "LogVerbosity setting is deprecated and will be removed in future versions. " + + "For logging configuration:\n" + + "1. Use an SLF4J implementation (recommended)\n" + + "2. Or implement CustomLogger interface and set via customLoggers property. " + + "Use CustomLogger if your slf4j implementation like logback, log4j2, etc. can't meet " + + "your specific logging requirements.", + level = DeprecationLevel.WARNING + ) override var logVerbosity: PNLogVerbosity = defaultConfiguration.logVerbosity override var heartbeatNotificationOptions: PNHeartbeatNotificationOptions = defaultConfiguration.heartbeatNotificationOptions @@ -114,7 +139,7 @@ class PNConfigurationImpl( set(value) { field = if (value < MINIMUM_PRESENCE_TIMEOUT) { - log.warn("Presence timeout is too low. Defaulting to: $MINIMUM_PRESENCE_TIMEOUT") + println("Presence timeout is too low. Defaulting to: $MINIMUM_PRESENCE_TIMEOUT") MINIMUM_PRESENCE_TIMEOUT } else { value @@ -164,6 +189,10 @@ class PNConfigurationImpl( override var certificatePinner: CertificatePinner? = defaultConfiguration.certificatePinner + @Deprecated( + message = "This setting is deprecated. Use customLoggers instead.", + level = DeprecationLevel.WARNING + ) override var httpLoggingInterceptor: HttpLoggingInterceptor? = defaultConfiguration.httpLoggingInterceptor override var sslSocketFactory: SSLSocketFactory? = defaultConfiguration.sslSocketFactory @@ -183,6 +212,8 @@ class PNConfigurationImpl( override var managePresenceListManually: Boolean = defaultConfiguration.managePresenceListManually + override var customLoggers: List? = defaultConfiguration.customLoggers + override fun build(): PNConfiguration { return PNConfigurationImpl( userId = userId, @@ -224,6 +255,7 @@ class PNConfigurationImpl( pnsdkSuffixes = pnsdkSuffixes, retryConfiguration = retryConfiguration, managePresenceListManually = managePresenceListManually, + customLoggers = customLoggers, ) } } diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/workers/SubscribeMessageProcessor.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/workers/SubscribeMessageProcessor.kt index dd3021eef6..487fd47cf8 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/workers/SubscribeMessageProcessor.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/main/kotlin/com/pubnub/internal/workers/SubscribeMessageProcessor.kt @@ -2,6 +2,9 @@ package com.pubnub.internal.workers import com.google.gson.JsonElement import com.google.gson.JsonNull +import com.pubnub.api.logging.LogConfig +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent import com.pubnub.api.models.consumer.files.PNDownloadableFile import com.pubnub.api.models.consumer.message_actions.PNMessageAction import com.pubnub.api.models.consumer.pubsub.BasePubSubResult @@ -18,6 +21,7 @@ import com.pubnub.api.v2.PNConfiguration.Companion.isValid import com.pubnub.internal.PubNubImpl import com.pubnub.internal.PubNubUtil import com.pubnub.internal.extension.tryDecryptMessage +import com.pubnub.internal.logging.LoggerManager import com.pubnub.internal.managers.DuplicationManager import com.pubnub.internal.models.consumer.pubsub.objects.PNObjectEventMessage import com.pubnub.internal.models.consumer.pubsub.objects.toApi @@ -26,13 +30,13 @@ import com.pubnub.internal.models.server.SubscribeMessage import com.pubnub.internal.models.server.files.FileUploadNotification import com.pubnub.internal.services.FilesService import com.pubnub.internal.subscribe.PRESENCE_CHANNEL_SUFFIX -import org.slf4j.LoggerFactory internal class SubscribeMessageProcessor( private val pubnub: PubNubImpl, private val duplicationManager: DuplicationManager, + private val logConfig: LogConfig, ) { - private val log = LoggerFactory.getLogger("SubscribeMessageProcessor") + private val log = LoggerManager.instance.getLogger(logConfig, this::class.java) companion object { internal const val TYPE_MESSAGE = 0 @@ -89,11 +93,15 @@ internal class SubscribeMessageProcessor( ) } else { val (extractedMessage, error) = - message.payload?.tryDecryptMessage(pubnub.configuration.cryptoModule, pubnub.mapper) + message.payload?.tryDecryptMessage(pubnub.cryptoModuleWithLogConfig, pubnub.mapper, log) ?: (null to null) if (extractedMessage == null) { - log.debug("unable to parse payload on #processIncomingMessages") + log.debug( + LogMessage( + message = LogMessageContent.Text("unable to parse payload on #processIncomingMessages"), + ) + ) } val customMessageType = message.customMessageType diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/api/crypto/CryptoModuleTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/api/crypto/CryptoModuleTest.kt index 129f1eb691..35c1a5fd4a 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/api/crypto/CryptoModuleTest.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/api/crypto/CryptoModuleTest.kt @@ -5,6 +5,7 @@ import com.pubnub.api.PubNubException import com.pubnub.api.crypto.cryptor.Cryptor import com.pubnub.api.crypto.data.EncryptedData import com.pubnub.api.crypto.data.EncryptedStreamData +import com.pubnub.api.logging.LogConfig import com.pubnub.internal.crypto.CryptoModuleImpl import com.pubnub.internal.crypto.cryptor.AesCbcCryptor import com.pubnub.internal.crypto.cryptor.LegacyCryptor @@ -348,6 +349,52 @@ class CryptoModuleTest { assertEquals(input, String(decrypted.readBytes())) } + @Test + fun `should inject LogConfig into CryptoModule created as LegacyCryptoModule`() { + // given + val cipherKey = "enigma" + val cryptoModule = CryptoModule.createLegacyCryptoModule(cipherKey) as CryptoModuleImpl + val logConfig = LogConfig( + pnInstanceId = "test-instance-id", + userId = "test-user-id" + ) + + // when + val cryptoModuleWithLogConfig = CryptoModuleImpl( + primaryCryptor = cryptoModule.primaryCryptor, + cryptorsForDecryptionOnly = cryptoModule.cryptorsForDecryptionOnly, + logConfig = logConfig + ) + + // then + assertEquals(logConfig, cryptoModuleWithLogConfig.logConfig) + assertTrue(cryptoModuleWithLogConfig.primaryCryptor is LegacyCryptor) + assertEquals(cryptoModule.cryptorsForDecryptionOnly, cryptoModuleWithLogConfig.cryptorsForDecryptionOnly) + } + + @Test + fun `should inject LogConfig into CryptoModule created as AesCbcCryptoModule`() { + // given + val cipherKey = "enigma" + val cryptoModule = CryptoModule.createAesCbcCryptoModule(cipherKey) as CryptoModuleImpl + val logConfig = LogConfig( + pnInstanceId = "test-instance-id", + userId = "test-user-id" + ) + + // when + val cryptoModuleWithLogConfig = CryptoModuleImpl( + primaryCryptor = cryptoModule.primaryCryptor, + cryptorsForDecryptionOnly = cryptoModule.cryptorsForDecryptionOnly, + logConfig = logConfig + ) + + // then + assertEquals(logConfig, cryptoModuleWithLogConfig.logConfig) + assertTrue(cryptoModuleWithLogConfig.primaryCryptor is AesCbcCryptor) + assertEquals(cryptoModule.cryptorsForDecryptionOnly, cryptoModuleWithLogConfig.cryptorsForDecryptionOnly) + } + companion object { @JvmStatic fun decryptStreamSource(): List = diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/api/crypto/cryptor/HeaderParserTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/api/crypto/cryptor/HeaderParserTest.kt index a8e3478c06..66429d9127 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/api/crypto/cryptor/HeaderParserTest.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/api/crypto/cryptor/HeaderParserTest.kt @@ -3,6 +3,7 @@ package com.pubnub.api.crypto.cryptor import com.pubnub.api.PubNubError import com.pubnub.api.PubNubException import com.pubnub.api.crypto.CryptoModule +import com.pubnub.api.logging.LogConfig import com.pubnub.internal.crypto.cryptor.HeaderParser import com.pubnub.internal.crypto.cryptor.ParseResult import org.hamcrest.MatcherAssert.assertThat @@ -19,7 +20,7 @@ class HeaderParserTest { @BeforeEach fun setUp() { - objectUnderTest = HeaderParser() + objectUnderTest = HeaderParser(LogConfig("defaultInstanceId", "user01")) } @Test diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/api/legacy/PubNubImplTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/api/legacy/PubNubImplTest.kt index d483fca73f..94475cb107 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/api/legacy/PubNubImplTest.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/api/legacy/PubNubImplTest.kt @@ -56,7 +56,7 @@ class PubNubImplTest : BaseTest() { fun getVersionAndTimeStamp() { val version = PubNubImpl.SDK_VERSION val timeStamp = PubNubImpl.timestamp() - assertEquals("10.5.8", version) + assertEquals("10.6.0", version) assertTrue(timeStamp > 0) } diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/api/legacy/endpoints/EndpointCoreTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/api/legacy/endpoints/EndpointCoreTest.kt index ec24775cf5..95383e22a5 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/api/legacy/endpoints/EndpointCoreTest.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/api/legacy/endpoints/EndpointCoreTest.kt @@ -7,11 +7,13 @@ import com.github.tomakehurst.wiremock.client.WireMock.stubFor import com.github.tomakehurst.wiremock.matching.UrlPattern import com.google.gson.JsonArray import com.google.gson.JsonObject +import com.pubnub.api.Endpoint import com.pubnub.api.PubNubException import com.pubnub.api.UserId import com.pubnub.api.enums.PNOperationType import com.pubnub.api.legacy.BaseTest import com.pubnub.api.retry.RetryableEndpointGroup +import com.pubnub.api.v2.PNConfigurationOverride import com.pubnub.internal.EndpointCore import com.pubnub.internal.PubNubImpl import com.pubnub.internal.v2.PNConfigurationImpl @@ -113,6 +115,13 @@ class EndpointCoreTest : BaseTest() { }.sync() } + @Test + fun testOverrideConfigurationIsLogged() { + fakeEndpoint { + assertEquals("myUUID", it["uuid"]) + }.sync() + } + @Test fun testUuid() { val expectedUuid = UserId(PubNubImpl.generateUUID()) @@ -326,6 +335,10 @@ class EndpointCoreTest : BaseTest() { override fun isAuthRequired() = false override fun getEndpointGroupName(): RetryableEndpointGroup = RetryableEndpointGroup.PUBLISH + + override fun overrideConfiguration(action: PNConfigurationOverride.Builder.() -> Unit): Endpoint { + return super.overrideConfiguration(action) + } } private fun fakeCall() = diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/api/legacy/endpoints/files/SendFileTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/api/legacy/endpoints/files/SendFileTest.kt index 9156c261d1..4fbf1b9d25 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/api/legacy/endpoints/files/SendFileTest.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/api/legacy/endpoints/files/SendFileTest.kt @@ -209,6 +209,7 @@ class SendFileTest : TestsWithFiles { val retryConfiguration = RetryConfiguration.None every { mockConfig.retryConfiguration } returns retryConfiguration every { mockPubNub.configuration } returns mockConfig + every { mockPubNub.logConfig } returns mockk() return mockPubNub } diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/api/legacy/endpoints/files/UploadFileTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/api/legacy/endpoints/files/UploadFileTest.kt index 367b633a1b..54afd33c8f 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/api/legacy/endpoints/files/UploadFileTest.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/api/legacy/endpoints/files/UploadFileTest.kt @@ -2,6 +2,7 @@ package com.pubnub.api.legacy.endpoints.files import com.pubnub.api.PubNubException import com.pubnub.api.crypto.CryptoModule +import com.pubnub.api.logging.LogConfig import com.pubnub.internal.endpoints.files.UploadFileEndpoint import com.pubnub.internal.models.server.files.FormField import com.pubnub.internal.services.S3Service @@ -24,6 +25,7 @@ import org.hamcrest.Matchers.`is` as iz class UploadFileTest : TestsWithFiles { private val s3Service: S3Service = mockk {} + private val logConfig = LogConfig("testPnInstanceId", "testUserId") @Test fun keyIsFirstInMultipart() { @@ -37,6 +39,7 @@ class UploadFileTest : TestsWithFiles { FormField("key", "keyValue"), listOf(FormField("other", "otherValue")), "https://s3.aws.com/bucket", + logConfig, ) every { s3Service.upload(any(), any()) } returns mockRetrofitSuccessfulCall {} @@ -68,6 +71,7 @@ class UploadFileTest : TestsWithFiles { FormField("key", "keyValue"), listOf(FormField("Content-Type", contentTypeValue)), "https://s3.aws.com/bucket", + logConfig, ) every { s3Service.upload(any(), any()) } returns mockRetrofitSuccessfulCall { null } @@ -94,6 +98,7 @@ class UploadFileTest : TestsWithFiles { FormField("key", "keyValue"), emptyList(), "https://s3.aws.com/bucket", + logConfig, ) every { s3Service.upload(any(), any()) } returns mockRetrofitSuccessfulCall { null } @@ -124,6 +129,7 @@ class UploadFileTest : TestsWithFiles { FormField("key", "keyValue"), emptyList(), "https://s3.aws.com/bucket", + logConfig, ) every { s3Service.upload(any(), any()) } returns mockRetrofitSuccessfulCall { null } @@ -154,6 +160,7 @@ class UploadFileTest : TestsWithFiles { FormField("key", "keyValue"), emptyList(), "https://s3.aws.com/bucket", + logConfig, ) every { s3Service.upload(any(), any()) } returns mockRetrofitErrorCall { diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/api/legacy/managers/SubscriptionManagerTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/api/legacy/managers/SubscriptionManagerTest.kt index af3350c1b7..69098e1975 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/api/legacy/managers/SubscriptionManagerTest.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/api/legacy/managers/SubscriptionManagerTest.kt @@ -18,6 +18,7 @@ import com.pubnub.api.crypto.CryptoModule import com.pubnub.api.enums.PNHeartbeatNotificationOptions import com.pubnub.api.enums.PNStatusCategory import com.pubnub.api.legacy.BaseTest +import com.pubnub.api.logging.LogConfig import com.pubnub.api.models.consumer.PNStatus import com.pubnub.api.models.consumer.pubsub.PNMessageResult import com.pubnub.api.models.consumer.pubsub.PNPresenceEventResult @@ -41,6 +42,7 @@ import java.util.concurrent.atomic.AtomicInteger class SubscriptionManagerTest : BaseTest() { private val subscribeUrlMatcher = Regex("(/v2/subscribe/[^/]+/)(.+)?(/.+)") private val presenceUrlMatcher = Regex("(/v2/presence/sub-key/[^/]+/channel/)(.+)(/.+)") + val logConfig = LogConfig("testPnInstanceId", "testUserId") // gets UrlPathPattern that matches the URL with channels in any order (order doesn't matter) private fun getMatchingUrlWithChannels(url: String): UrlPathPattern { @@ -374,7 +376,7 @@ class SubscriptionManagerTest : BaseTest() { ) { val requests = findAll(getRequestedFor(urlMatching("/v2/subscribe.*"))) assertTrue(requests.size > 0) - assertEquals("Message", MapperManager().elementToString(pnMessageResult.message, "text")) + assertEquals("Message", MapperManager(logConfig).elementToString(pnMessageResult.message, "text")) assertEquals("coolChannel", pnMessageResult.channel) assertEquals(null, pnMessageResult.subscription) assertEquals("Publisher-A", pnMessageResult.publisher) @@ -827,7 +829,7 @@ class SubscriptionManagerTest : BaseTest() { ) { val requests = findAll(getRequestedFor(urlMatching("/v2/subscribe.*"))) assertTrue(requests.size > 0) - assertEquals("Message", MapperManager().elementToString(pnMessageResult.message, "text")) + assertEquals("Message", MapperManager(logConfig).elementToString(pnMessageResult.message, "text")) assertEquals("coolChannel", pnMessageResult.channel) assertEquals("coolChannelGroup", pnMessageResult.subscription) gotMessage.set(true) @@ -1705,7 +1707,7 @@ class SubscriptionManagerTest : BaseTest() { ) { val requests = findAll(getRequestedFor(urlMatching("/v2/subscribe.*"))) assertTrue(requests.size > 0) - assertEquals("hey", MapperManager().elementToString(pnMessageResult.message, "text")) + assertEquals("hey", MapperManager(logConfig).elementToString(pnMessageResult.message, "text")) atomic.addAndGet(1) } }, diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/eventengine/EffectDispatcherTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/eventengine/EffectDispatcherTest.kt index cf23a352aa..6ac621b31b 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/eventengine/EffectDispatcherTest.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/eventengine/EffectDispatcherTest.kt @@ -1,5 +1,6 @@ package com.pubnub.internal.eventengine +import com.pubnub.api.logging.LogConfig import com.pubnub.internal.subscribe.eventengine.effect.SubscribeEffectInvocation import io.mockk.every import io.mockk.mockk @@ -14,6 +15,7 @@ import java.util.concurrent.ScheduledExecutorService class EffectDispatcherTest { private val executorService: ScheduledExecutorService = mockk() + private val logConfig: LogConfig = LogConfig(pnInstanceId = "testInstanceId", userId = "testUserId") internal sealed class TestEffectInvocation(override val type: EffectInvocationType) : EffectInvocation { override val id: String = this::class.java.simpleName @@ -54,6 +56,7 @@ class EffectDispatcherTest { EffectDispatcher( effectFactory = EffectHandlerFactoryImpl(), managedEffects = managedEffects, + logConfig = logConfig, effectSource = QueueSinkSource(), executorService = executorService, ) @@ -73,6 +76,7 @@ class EffectDispatcherTest { EffectDispatcher( effectFactory = EffectHandlerFactoryImpl(), managedEffects = managedEffects, + logConfig = logConfig, effectSource = QueueSinkSource(), executorService = executorService, ) @@ -93,6 +97,7 @@ class EffectDispatcherTest { EffectDispatcher( effectFactory = EffectHandlerFactoryImpl(), managedEffects = managedEffects, + logConfig = logConfig, effectSource = QueueSinkSource(), executorService = executorService, ) @@ -117,6 +122,7 @@ class EffectDispatcherTest { EffectDispatcher( effectFactory = effectHandlerFactory, managedEffects = managedEffects, + logConfig = logConfig, effectSource = QueueSinkSource(), executorService = executorService, ) @@ -140,6 +146,7 @@ class EffectDispatcherTest { EffectDispatcher( effectFactory = effectFactory, managedEffects = managedEffects, + logConfig = logConfig, effectSource = QueueSinkSource(), executorService = executorService, ) diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/eventengine/EventEngineTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/eventengine/EventEngineTest.kt index fd96ac9cf7..ac86328432 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/eventengine/EventEngineTest.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/eventengine/EventEngineTest.kt @@ -1,5 +1,6 @@ package com.pubnub.internal.eventengine +import com.pubnub.api.logging.LogConfig import com.pubnub.contract.subscribe.eventEngine.state.TestSinkSource import io.mockk.mockk import org.junit.jupiter.api.Assertions @@ -31,6 +32,7 @@ class EventEngineTest { effectSink = eventEngineConf.effectSink, eventSource = eventEngineConf.eventSource, currentState = TestState, + logConfig = LogConfig(pnInstanceId = "EventEngineTest", userId = "TestUserId"), executorService = executorService, ) diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/extension/JsonElementTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/extension/JsonElementTest.kt index 88a4e0a000..c745f7cdad 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/extension/JsonElementTest.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/extension/JsonElementTest.kt @@ -7,6 +7,9 @@ import com.google.gson.JsonObject import com.google.gson.JsonPrimitive import com.pubnub.api.PubNubError import com.pubnub.api.crypto.CryptoModule +import com.pubnub.api.logging.LogConfig +import com.pubnub.internal.logging.LoggerManager +import com.pubnub.internal.logging.PNLogger import com.pubnub.internal.managers.MapperManager import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertNull @@ -17,6 +20,7 @@ import org.junit.jupiter.params.provider.MethodSource class JsonElementTest { companion object { val gson = Gson() + val logConfig = LogConfig("testPnInstanceId", "testUserId") @JvmStatic fun cryptoModuleConfiguration(): List { @@ -81,10 +85,11 @@ class JsonElementTest { objectUnderTest = JsonPrimitive(unencryptedMessage) val cipherKey = "enigma" val cryptoModule = CryptoModule.createLegacyCryptoModule(cipherKey = cipherKey, randomIv = true) - val mapper = MapperManager() + val mapper = MapperManager(logConfig) + val logger: PNLogger = LoggerManager.instance.getLogger(LogConfig("testPnInstanceId", "testUser"), this::class.java) // when - val (jsonElement, errorMessage) = objectUnderTest.tryDecryptMessage(cryptoModule, mapper) + val (jsonElement, errorMessage) = objectUnderTest.tryDecryptMessage(cryptoModule, mapper, logger) // then assertEquals(objectUnderTest, jsonElement) @@ -100,10 +105,11 @@ class JsonElementTest { ) { // given objectUnderTest = JsonPrimitive(encryptedMessage) - val mapper = MapperManager() + val mapper = MapperManager(logConfig) + val logger: PNLogger = LoggerManager.instance.getLogger(LogConfig("testPnInstanceId", "testUser"), this::class.java) // when - val (jsonElement, errorMessage) = objectUnderTest.tryDecryptMessage(cryptoModule, mapper) + val (jsonElement, errorMessage) = objectUnderTest.tryDecryptMessage(cryptoModule, mapper, logger) // then assertEquals(message, jsonElement) @@ -119,10 +125,11 @@ class JsonElementTest { ) { // given objectUnderTest = message - val mapper = MapperManager() + val mapper = MapperManager(logConfig) + val logger: PNLogger = LoggerManager.instance.getLogger(LogConfig("testPnInstanceId", "testUser"), this::class.java) // when - val (jsonElement, errorMessage) = objectUnderTest.tryDecryptMessage(cryptoModule, mapper) + val (jsonElement, errorMessage) = objectUnderTest.tryDecryptMessage(cryptoModule, mapper, logger) // then assertEquals(objectUnderTest, jsonElement) @@ -139,10 +146,11 @@ class JsonElementTest { // given val messageWithPNOther = generateMessageWithPNOther(JsonPrimitive(encryptedMessage)) objectUnderTest = messageWithPNOther - val mapper = MapperManager() + val mapper = MapperManager(logConfig) + val logger: PNLogger = LoggerManager.instance.getLogger(LogConfig("testPnInstanceId", "testUser"), this::class.java) // when - val (jsonElement, errorMessage) = objectUnderTest.tryDecryptMessage(cryptoModule, mapper) + val (jsonElement, errorMessage) = objectUnderTest.tryDecryptMessage(cryptoModule, mapper, logger) // then assertEquals(messageWithPNOther, jsonElement) diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/logging/CompositeLoggerTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/logging/CompositeLoggerTest.kt new file mode 100644 index 0000000000..b8030124e2 --- /dev/null +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/logging/CompositeLoggerTest.kt @@ -0,0 +1,511 @@ +package com.pubnub.internal.logging + +import com.pubnub.api.logging.CustomLogger +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent +import com.pubnub.api.logging.LogMessageType +import io.mockk.every +import io.mockk.mockk +import io.mockk.slot +import io.mockk.verify +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertNull +import org.junit.jupiter.api.Test +import org.slf4j.Logger +import org.slf4j.event.Level + +class CompositeLoggerTest { + private val mockSlf4jLogger = mockk(relaxed = true) + private val mockToPortalLogger = mockk(relaxed = true) + private val mockCustomLogger1 = mockk(relaxed = true) + private val mockCustomLogger2 = mockk(relaxed = true) + private val testInstanceId = "test-instance-id" + private val testLocation = "CompositeLoggerTest" + + private fun createTestLogMessage(): LogMessage { + return LogMessage( + message = LogMessageContent.Text("test message"), + details = "test details", + type = LogMessageType.TEXT, + location = "test-location" + ) + } + + private fun createTestLogMessageWithNulls(): LogMessage { + return LogMessage( + message = LogMessageContent.Text("test message"), + details = null, + type = LogMessageType.TEXT, + location = "test-location", + pubNubId = null, + logLevel = null + ) + } + + @Test + fun `should delegate trace message to all loggers with enhanced message`() { + val customLoggers = listOf(mockCustomLogger1, mockCustomLogger2) + val compositeLogger = CompositeLogger( + slf4jLogger = mockSlf4jLogger, + location = testLocation, + pnInstanceId = testInstanceId, + toPortalLogger = mockToPortalLogger, + customLoggers = customLoggers + ) + + val originalMessage = createTestLogMessage() + val portalLogSlot = slot() + val customLog1Slot = slot() + val customLog2Slot = slot() + + every { mockToPortalLogger.trace(capture(portalLogSlot)) } returns Unit + every { mockCustomLogger1.trace(logMessage = capture(customLog1Slot)) } returns Unit + every { mockCustomLogger2.trace(logMessage = capture(customLog2Slot)) } returns Unit + + compositeLogger.trace(originalMessage) + + verify { mockSlf4jLogger.trace(any()) } + verify { mockToPortalLogger.trace(any()) } + verify { mockCustomLogger1.trace(logMessage = any()) } + verify { mockCustomLogger1.trace(message = any()) } + verify { mockCustomLogger2.trace(logMessage = any()) } + verify { mockCustomLogger2.trace(message = any()) } + + // Verify enhanced messages have correct pubNubId and logLevel + assertEquals(testInstanceId, portalLogSlot.captured.pubNubId) + assertEquals(Level.TRACE, portalLogSlot.captured.logLevel) + assertEquals(testInstanceId, customLog1Slot.captured.pubNubId) + assertEquals(Level.TRACE, customLog1Slot.captured.logLevel) + assertEquals(testInstanceId, customLog2Slot.captured.pubNubId) + assertEquals(Level.TRACE, customLog2Slot.captured.logLevel) + } + + @Test + fun `should delegate debug message to all loggers with enhanced message`() { + val customLoggers = listOf(mockCustomLogger1, mockCustomLogger2) + val compositeLogger = CompositeLogger( + slf4jLogger = mockSlf4jLogger, + location = testLocation, + pnInstanceId = testInstanceId, + toPortalLogger = mockToPortalLogger, + customLoggers = customLoggers + ) + + val originalMessage = createTestLogMessage() + val portalLogSlot = slot() + val customLog1Slot = slot() + val customLog2Slot = slot() + + every { mockToPortalLogger.debug(capture(portalLogSlot)) } returns Unit + every { mockCustomLogger1.debug(logMessage = capture(customLog1Slot)) } returns Unit + every { mockCustomLogger2.debug(logMessage = capture(customLog2Slot)) } returns Unit + + compositeLogger.debug(originalMessage) + + verify { mockSlf4jLogger.debug(any()) } + verify { mockToPortalLogger.debug(any()) } + verify { mockCustomLogger1.debug(logMessage = any()) } + verify { mockCustomLogger1.debug(message = any()) } + verify { mockCustomLogger2.debug(logMessage = any()) } + verify { mockCustomLogger2.debug(message = any()) } + + // Verify enhanced messages have correct pubNubId and logLevel + assertEquals(testInstanceId, portalLogSlot.captured.pubNubId) + assertEquals(Level.DEBUG, portalLogSlot.captured.logLevel) + assertEquals(testInstanceId, customLog1Slot.captured.pubNubId) + assertEquals(Level.DEBUG, customLog1Slot.captured.logLevel) + assertEquals(testInstanceId, customLog2Slot.captured.pubNubId) + assertEquals(Level.DEBUG, customLog2Slot.captured.logLevel) + } + + @Test + fun `should delegate info message to all loggers with enhanced message`() { + val customLoggers = listOf(mockCustomLogger1, mockCustomLogger2) + val compositeLogger = CompositeLogger( + slf4jLogger = mockSlf4jLogger, + location = testLocation, + pnInstanceId = testInstanceId, + toPortalLogger = mockToPortalLogger, + customLoggers = customLoggers + ) + + val originalMessage = createTestLogMessage() + val portalLogSlot = slot() + val customLog1Slot = slot() + val customLog2Slot = slot() + + every { mockToPortalLogger.info(capture(portalLogSlot)) } returns Unit + every { mockCustomLogger1.info(logMessage = capture(customLog1Slot)) } returns Unit + every { mockCustomLogger2.info(logMessage = capture(customLog2Slot)) } returns Unit + + compositeLogger.info(originalMessage) + + verify { mockSlf4jLogger.info(any()) } + verify { mockToPortalLogger.info(any()) } + verify { mockCustomLogger1.info(logMessage = any()) } + verify { mockCustomLogger1.info(message = any()) } + verify { mockCustomLogger2.info(logMessage = any()) } + verify { mockCustomLogger2.info(message = any()) } + + // Verify enhanced messages have correct pubNubId and logLevel + assertEquals(testInstanceId, portalLogSlot.captured.pubNubId) + assertEquals(Level.INFO, portalLogSlot.captured.logLevel) + assertEquals(testInstanceId, customLog1Slot.captured.pubNubId) + assertEquals(Level.INFO, customLog1Slot.captured.logLevel) + assertEquals(testInstanceId, customLog2Slot.captured.pubNubId) + assertEquals(Level.INFO, customLog2Slot.captured.logLevel) + } + + @Test + fun `should delegate warn message to all loggers with enhanced message`() { + val customLoggers = listOf(mockCustomLogger1, mockCustomLogger2) + val compositeLogger = CompositeLogger( + slf4jLogger = mockSlf4jLogger, + location = testLocation, + pnInstanceId = testInstanceId, + toPortalLogger = mockToPortalLogger, + customLoggers = customLoggers + ) + + val originalMessage = createTestLogMessage() + val portalLogSlot = slot() + val customLog1Slot = slot() + val customLog2Slot = slot() + + every { mockToPortalLogger.warn(capture(portalLogSlot)) } returns Unit + every { mockCustomLogger1.warn(logMessage = capture(customLog1Slot)) } returns Unit + every { mockCustomLogger2.warn(logMessage = capture(customLog2Slot)) } returns Unit + + compositeLogger.warn(originalMessage) + + verify { mockSlf4jLogger.warn(any()) } + verify { mockToPortalLogger.warn(any()) } + verify { mockCustomLogger1.warn(logMessage = any()) } + verify { mockCustomLogger1.warn(message = any()) } + verify { mockCustomLogger2.warn(logMessage = any()) } + verify { mockCustomLogger2.warn(message = any()) } + + // Verify enhanced messages have correct pubNubId and logLevel + assertEquals(testInstanceId, portalLogSlot.captured.pubNubId) + assertEquals(Level.WARN, portalLogSlot.captured.logLevel) + assertEquals(testInstanceId, customLog1Slot.captured.pubNubId) + assertEquals(Level.WARN, customLog1Slot.captured.logLevel) + assertEquals(testInstanceId, customLog2Slot.captured.pubNubId) + assertEquals(Level.WARN, customLog2Slot.captured.logLevel) + } + + @Test + fun `should delegate error message to all loggers with enhanced message`() { + val customLoggers = listOf(mockCustomLogger1, mockCustomLogger2) + val compositeLogger = CompositeLogger( + slf4jLogger = mockSlf4jLogger, + location = testLocation, + pnInstanceId = testInstanceId, + toPortalLogger = mockToPortalLogger, + customLoggers = customLoggers + ) + + val originalMessage = createTestLogMessage() + val portalLogSlot = slot() + val customLog1Slot = slot() + val customLog2Slot = slot() + + every { mockToPortalLogger.error(capture(portalLogSlot)) } returns Unit + every { mockCustomLogger1.error(logMessage = capture(customLog1Slot)) } returns Unit + every { mockCustomLogger2.error(logMessage = capture(customLog2Slot)) } returns Unit + + compositeLogger.error(originalMessage) + + verify { mockSlf4jLogger.error(any()) } + verify { mockToPortalLogger.error(any()) } + verify { mockCustomLogger1.error(logMessage = any()) } + verify { mockCustomLogger1.error(message = any()) } + verify { mockCustomLogger2.error(logMessage = any()) } + verify { mockCustomLogger2.error(message = any()) } + + // Verify enhanced messages have correct pubNubId and logLevel + assertEquals(testInstanceId, portalLogSlot.captured.pubNubId) + assertEquals(Level.ERROR, portalLogSlot.captured.logLevel) + assertEquals(testInstanceId, customLog1Slot.captured.pubNubId) + assertEquals(Level.ERROR, customLog1Slot.captured.logLevel) + assertEquals(testInstanceId, customLog2Slot.captured.pubNubId) + assertEquals(Level.ERROR, customLog2Slot.captured.logLevel) + } + + @Test + fun `should work without portal logger`() { + val customLoggers = listOf(mockCustomLogger1) + val compositeLogger = CompositeLogger( + slf4jLogger = mockSlf4jLogger, + location = testLocation, + pnInstanceId = testInstanceId, + toPortalLogger = null, + customLoggers = customLoggers + ) + + val originalMessage = createTestLogMessage() + + compositeLogger.info(originalMessage) + + verify { mockSlf4jLogger.info(any()) } + verify { mockCustomLogger1.info(logMessage = any()) } + verify { mockCustomLogger1.info(message = any()) } + } + + @Test + fun `should work without custom loggers`() { + val compositeLogger = CompositeLogger( + slf4jLogger = mockSlf4jLogger, + location = testLocation, + pnInstanceId = testInstanceId, + toPortalLogger = mockToPortalLogger, + customLoggers = null + ) + + val testMessage = createTestLogMessage() + + compositeLogger.info(testMessage) + + verify { mockSlf4jLogger.info(any()) } + verify { mockToPortalLogger.info(any()) } + } + + @Test + fun `should work with empty custom loggers list`() { + val compositeLogger = CompositeLogger( + slf4jLogger = mockSlf4jLogger, + location = testLocation, + pnInstanceId = testInstanceId, + toPortalLogger = mockToPortalLogger, + customLoggers = emptyList() + ) + + val testMessage = createTestLogMessage() + + compositeLogger.info(testMessage) + + verify { mockSlf4jLogger.info(any()) } + verify { mockToPortalLogger.info(any()) } + } + + @Test + fun `should isolate custom logger failures`() { + every { mockCustomLogger1.name } returns "FailingLogger1" + every { mockCustomLogger1.info(logMessage = any()) } throws RuntimeException("Logger 1 failed") + every { mockCustomLogger2.name } returns "WorkingLogger2" + + val customLoggers = listOf(mockCustomLogger1, mockCustomLogger2) + val compositeLogger = CompositeLogger( + slf4jLogger = mockSlf4jLogger, + location = testLocation, + pnInstanceId = testInstanceId, + toPortalLogger = mockToPortalLogger, + customLoggers = customLoggers + ) + + val testMessage = createTestLogMessage() + + compositeLogger.info(testMessage) + + // Primary loggers should still work + verify { mockSlf4jLogger.info(any()) } + verify { mockToPortalLogger.info(any()) } + + // Working custom logger should still be called + verify { mockCustomLogger2.info(logMessage = any()) } + verify { mockCustomLogger2.info(message = any()) } + + // Error should be logged about the failing logger + verify { mockSlf4jLogger.error(match { it.contains("FailingLogger1") && it.contains("failed") }) } + verify { mockToPortalLogger.error(any()) } + } + + @Test + fun `should handle failure in error reporting`() { + every { mockCustomLogger1.name } returns "FailingLogger" + every { mockCustomLogger1.info(logMessage = any()) } throws RuntimeException("Logger failed") + every { mockSlf4jLogger.error(any()) } throws RuntimeException("SLF4J also failed") + + val customLoggers = listOf(mockCustomLogger1) + val compositeLogger = CompositeLogger( + slf4jLogger = mockSlf4jLogger, + location = testLocation, + pnInstanceId = testInstanceId, + toPortalLogger = mockToPortalLogger, + customLoggers = customLoggers + ) + + val testMessage = createTestLogMessage() + + // Should not throw exception even when error reporting fails + compositeLogger.info(testMessage) + + verify { mockSlf4jLogger.info(any()) } + verify { mockToPortalLogger.info(any()) } + } + + @Test + fun `should use correct instance id in error messages`() { + every { mockCustomLogger1.name } returns "FailingLogger" + every { mockCustomLogger1.info(logMessage = any()) } throws RuntimeException("Test failure") + + val customLoggers = listOf(mockCustomLogger1) + val compositeLogger = CompositeLogger( + slf4jLogger = mockSlf4jLogger, + location = testLocation, + pnInstanceId = testInstanceId, + toPortalLogger = mockToPortalLogger, + customLoggers = customLoggers + ) + + val testMessage = createTestLogMessage() + val errorMessageSlot = slot() + every { mockToPortalLogger.error(capture(errorMessageSlot)) } returns Unit + + compositeLogger.info(testMessage) + + verify { mockToPortalLogger.error(any()) } + val capturedErrorMessage = errorMessageSlot.captured + assertEquals(testInstanceId, capturedErrorMessage.pubNubId) + assertEquals("CompositeLogger", capturedErrorMessage.location) + assertEquals(Level.ERROR, capturedErrorMessage.logLevel) + assertEquals(LogMessageType.ERROR, capturedErrorMessage.type) + } + + @Test + fun `should be thread safe with concurrent access`() { + val customLoggers = listOf(mockCustomLogger1, mockCustomLogger2) + val compositeLogger = CompositeLogger( + slf4jLogger = mockSlf4jLogger, + location = testLocation, + pnInstanceId = testInstanceId, + toPortalLogger = mockToPortalLogger, + customLoggers = customLoggers + ) + + val messages = (1..100).map { i -> + LogMessage( + message = LogMessageContent.Text("message $i"), + type = LogMessageType.TEXT, + location = "thread-test" + ) + } + + // Execute logging from multiple threads concurrently + val threads = (1..10).map { threadId -> + Thread { + messages.forEach { message -> + compositeLogger.info(message) + } + } + } + + threads.forEach { it.start() } + threads.forEach { it.join() } + + // Verify that all messages were processed (1000 total: 10 threads * 100 messages each) + verify(exactly = 1000) { mockSlf4jLogger.info(any()) } + verify(exactly = 1000) { mockToPortalLogger.info(any()) } + verify(exactly = 1000) { mockCustomLogger1.info(logMessage = any()) } + verify(exactly = 1000) { mockCustomLogger2.info(logMessage = any()) } + } + + @Test + fun `should preserve all original message fields including timestamp`() { + val compositeLogger = CompositeLogger( + slf4jLogger = mockSlf4jLogger, + location = testLocation, + pnInstanceId = testInstanceId, + toPortalLogger = mockToPortalLogger, + customLoggers = null + ) + + val customTimestamp = "23:59:59.999" + val originalMessage = LogMessage( + message = LogMessageContent.Object(mapOf("key" to "value")), + details = "important details", + type = LogMessageType.OBJECT, + location = "test-location", + timestamp = customTimestamp + ) + + val capturedSlot = slot() + every { mockToPortalLogger.info(capture(capturedSlot)) } returns Unit + + compositeLogger.info(originalMessage) + + val enhancedMessage = capturedSlot.captured + + // Verify original fields are preserved + assertEquals("test-location", enhancedMessage.location) + assertEquals(LogMessageType.OBJECT, enhancedMessage.type) + assertEquals(originalMessage.message, enhancedMessage.message) + assertEquals("important details", enhancedMessage.details) + assertEquals(customTimestamp, enhancedMessage.timestamp) + + // Verify injected fields + assertEquals(testInstanceId, enhancedMessage.pubNubId) + assertEquals(Level.INFO, enhancedMessage.logLevel) + } + + @Test + fun `should handle null fields gracefully`() { + val compositeLogger = CompositeLogger( + slf4jLogger = mockSlf4jLogger, + location = testLocation, + pnInstanceId = testInstanceId, + toPortalLogger = mockToPortalLogger, + customLoggers = null + ) + + val messageWithNulls = createTestLogMessageWithNulls() + val capturedSlot = slot() + every { mockToPortalLogger.debug(capture(capturedSlot)) } returns Unit + + compositeLogger.debug(messageWithNulls) + + val enhancedMessage = capturedSlot.captured + + // Verify null fields are preserved as null + assertNull(enhancedMessage.details) + + // Verify injected fields override any null values + assertEquals(testInstanceId, enhancedMessage.pubNubId) + assertEquals(Level.DEBUG, enhancedMessage.logLevel) + + // Verify required fields are preserved + assertEquals("test-location", enhancedMessage.location) + assertEquals(LogMessageType.TEXT, enhancedMessage.type) + } + + @Test + fun `should override existing pubNubId and logLevel in original message`() { + val compositeLogger = CompositeLogger( + slf4jLogger = mockSlf4jLogger, + location = testLocation, + pnInstanceId = testInstanceId, + toPortalLogger = mockToPortalLogger, + customLoggers = null + ) + + // Create message with different pubNubId and logLevel + val messageWithExistingValues = LogMessage( + message = LogMessageContent.Text("test message"), + type = LogMessageType.TEXT, + location = "test-location", + pubNubId = "different-instance-id", + logLevel = Level.ERROR // This should be overridden to WARN + ) + + val capturedSlot = slot() + every { mockToPortalLogger.warn(capture(capturedSlot)) } returns Unit + + compositeLogger.warn(messageWithExistingValues) + + val enhancedMessage = capturedSlot.captured + + // Verify values are overridden with CompositeLogger's values + assertEquals(testInstanceId, enhancedMessage.pubNubId) + assertEquals(Level.WARN, enhancedMessage.logLevel) + } +} diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/logging/ConfigurationLoggerTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/logging/ConfigurationLoggerTest.kt new file mode 100644 index 0000000000..5f9ff0ffc0 --- /dev/null +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/logging/ConfigurationLoggerTest.kt @@ -0,0 +1,289 @@ +package com.pubnub.internal.logging + +import com.pubnub.api.UserId +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent +import com.pubnub.api.logging.LogMessageType +import com.pubnub.internal.v2.PNConfigurationImpl +import io.mockk.mockk +import io.mockk.slot +import io.mockk.verify +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertNotNull +import org.junit.jupiter.api.Assertions.assertNull +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test + +class ConfigurationLoggerTest { + @Test + fun `should log configuration with all required fields`() { + // Given + val mockLogger = mockk(relaxed = true) + val logMessageSlot = slot() + + val config = PNConfigurationImpl( + userId = UserId("test-user"), + subscribeKey = "test-sub-key" + ) + val instanceId = "test-instance-123" + val testClass = String::class.java + + // When + ConfigurationLogger.logConfiguration(config, mockLogger, instanceId, testClass) + + // Then + verify { mockLogger.debug(capture(logMessageSlot)) } + + val capturedMessage = logMessageSlot.captured + assertNull(capturedMessage.pubNubId) + assertNull(capturedMessage.logLevel) + assertEquals(testClass.toString(), capturedMessage.location) + assertEquals(LogMessageType.OBJECT, capturedMessage.type) + assertEquals("Configuration logged", capturedMessage.details) + + val configSummary = capturedMessage.message as LogMessageContent.Object + assertNotNull(configSummary.message) + assertEquals("test-user", configSummary.message["userId"]) + assertEquals("test-sub-key", configSummary.message["subscribeKey"]) + } + + @Test + fun `should handle optional fields correctly`() { + // Given + val mockLogger = mockk(relaxed = true) + val logMessageSlot = slot() + + val config = PNConfigurationImpl( + userId = UserId("test-user"), + subscribeKey = "test-sub-key", + publishKey = "test-pub-key", + secretKey = "test-secret", + authKey = "test-auth", + origin = "custom-origin" + ) + val instanceId = "test-instance-123" + val testClass = Int::class.java + + // When + ConfigurationLogger.logConfiguration(config, mockLogger, instanceId, testClass) + + // Then + verify { mockLogger.debug(capture(logMessageSlot)) } + + val capturedMessage = logMessageSlot.captured + val configSummary = capturedMessage.message as LogMessageContent.Object + + assertEquals("test-pub-key", configSummary.message["publishKey"]) + assertEquals("set: *****", configSummary.message["secretKey"]) + assertEquals("(@Deprecated) set: *****", configSummary.message["authKey"]) + assertEquals("custom-origin", configSummary.message["origin"]) + } + + @Test + fun `should handle null and empty optional fields`() { + // Given + val mockLogger = mockk(relaxed = true) + val logMessageSlot = slot() + + val config = PNConfigurationImpl( + userId = UserId("test-user"), + subscribeKey = "test-sub-key", + publishKey = "", + secretKey = "", + authKey = "", + origin = "" + ) + val instanceId = "test-instance-123" + val testClass = Boolean::class.java + + // When + ConfigurationLogger.logConfiguration(config, mockLogger, instanceId, testClass) + + // Then + verify { mockLogger.debug(capture(logMessageSlot)) } + + val capturedMessage = logMessageSlot.captured + val configSummary = capturedMessage.message as LogMessageContent.Object + + assertEquals("not set", configSummary.message["publishKey"]) + assertEquals("not set", configSummary.message["secretKey"]) + assertEquals("not set", configSummary.message["authKey"]) + assertEquals("default", configSummary.message["origin"]) + } + + @Test + fun `should handle custom loggers configuration`() { + // Given + val mockLogger = mockk(relaxed = true) + val logMessageSlot = slot() + val customLogger = mockk() + + val config = PNConfigurationImpl( + userId = UserId("test-user"), + subscribeKey = "test-sub-key", + customLoggers = listOf(customLogger) + ) + val instanceId = "test-instance-123" + val testClass = List::class.java + + // When + ConfigurationLogger.logConfiguration(config, mockLogger, instanceId, testClass) + + // Then + verify { mockLogger.debug(capture(logMessageSlot)) } + + val capturedMessage = logMessageSlot.captured + val configSummary = capturedMessage.message as LogMessageContent.Object + + assertEquals("enabled (1 logger)", configSummary.message["customLoggers"]) + } + + @Test + fun `should handle multiple custom loggers`() { + // Given + val mockLogger = mockk(relaxed = true) + val logMessageSlot = slot() + val customLogger1 = mockk() + val customLogger2 = mockk() + + val config = PNConfigurationImpl( + userId = UserId("test-user"), + subscribeKey = "test-sub-key", + customLoggers = listOf(customLogger1, customLogger2) + ) + val instanceId = "test-instance-123" + val testClass = Map::class.java + + // When + ConfigurationLogger.logConfiguration(config, mockLogger, instanceId, testClass) + + // Then + verify { mockLogger.debug(capture(logMessageSlot)) } + + val capturedMessage = logMessageSlot.captured + val configSummary = capturedMessage.message as LogMessageContent.Object + + assertEquals("enabled (2 loggers)", configSummary.message["customLoggers"]) + } + + @Test + fun `should handle null custom loggers`() { + // Given + val mockLogger = mockk(relaxed = true) + val logMessageSlot = slot() + + val config = PNConfigurationImpl( + userId = UserId("test-user"), + subscribeKey = "test-sub-key", + customLoggers = null + ) + val instanceId = "test-instance-123" + val testClass = Set::class.java + + // When + ConfigurationLogger.logConfiguration(config, mockLogger, instanceId, testClass) + + // Then + verify { mockLogger.debug(capture(logMessageSlot)) } + + val capturedMessage = logMessageSlot.captured + val configSummary = capturedMessage.message as LogMessageContent.Object + + assertEquals("not set", configSummary.message["customLoggers"]) + } + + @Test + fun `should handle crypto module configuration`() { + // Given + val mockLogger = mockk(relaxed = true) + val logMessageSlot = slot() + val cryptoModule = mockk() + + val config = PNConfigurationImpl( + userId = UserId("test-user"), + subscribeKey = "test-sub-key", + cryptoModule = cryptoModule + ) + val instanceId = "test-instance-123" + val testClass = Array::class.java + + // When + ConfigurationLogger.logConfiguration(config, mockLogger, instanceId, testClass) + + // Then + verify { mockLogger.debug(capture(logMessageSlot)) } + + val capturedMessage = logMessageSlot.captured + val configSummary = capturedMessage.message as LogMessageContent.Object + + assertEquals("enabled", configSummary.message["cryptoModule"]) + } + + @Test + fun `should handle disabled crypto module`() { + // Given + val mockLogger = mockk(relaxed = true) + val logMessageSlot = slot() + + val config = PNConfigurationImpl( + userId = UserId("test-user"), + subscribeKey = "test-sub-key", + cryptoModule = null + ) + val instanceId = "test-instance-123" + val testClass = CharSequence::class.java + + // When + ConfigurationLogger.logConfiguration(config, mockLogger, instanceId, testClass) + + // Then + verify { mockLogger.debug(capture(logMessageSlot)) } + + val capturedMessage = logMessageSlot.captured + val configSummary = capturedMessage.message as LogMessageContent.Object + + assertEquals("disabled", configSummary.message["cryptoModule"]) + } + + @Test + fun `should include all configuration fields in summary`() { + // Given + val mockLogger = mockk(relaxed = true) + val logMessageSlot = slot() + + val config = PNConfigurationImpl( + userId = UserId("test-user"), + subscribeKey = "test-sub-key" + ) + val instanceId = "test-instance-123" + val testClass = Any::class.java + + // When + ConfigurationLogger.logConfiguration(config, mockLogger, instanceId, testClass) + + // Then + verify { mockLogger.debug(capture(logMessageSlot)) } + + val capturedMessage = logMessageSlot.captured + val configSummary = capturedMessage.message as LogMessageContent.Object + + // Verify all expected fields are present + val expectedFields = listOf( + "userId", "subscribeKey", "publishKey", "secretKey", "secure", "origin", + "logVerbosity", "cacheBusting", "connectTimeout", "subscribeTimeout", + "nonSubscribeReadTimeout", "presenceTimeout", "heartbeatInterval", + "heartbeatNotificationOptions", "suppressLeaveEvents", "maintainPresenceState", + "authKey", "authToken", "filterExpression", "dedupOnSubscribe", + "maximumMessagesCacheSize", "retryConfiguration", "fileMessagePublishRetryLimit", + "includeInstanceIdentifier", "includeRequestIdentifier", "pnsdkSuffixes", + "cryptoModule", "managePresenceListManually", "customLoggers", "proxy", + "proxySelector", "proxyAuthenticator", "maximumConnections", "httpLoggingInterceptor", + "sslSocketFactory", "x509ExtendedTrustManager", "connectionSpec", + "hostnameVerifier", "certificatePinner", "googleAppEngineNetworking", "instanceId" + ) + + expectedFields.forEach { field -> + assertTrue(configSummary.message.containsKey(field), "Missing field: $field") + } + } +} diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/logging/LoggerManagerTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/logging/LoggerManagerTest.kt new file mode 100644 index 0000000000..91c9084ec9 --- /dev/null +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/logging/LoggerManagerTest.kt @@ -0,0 +1,219 @@ +package com.pubnub.internal.logging + +import com.pubnub.api.logging.CustomLogger +import com.pubnub.api.logging.LogConfig +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent +import com.pubnub.api.logging.LogMessageType +import io.mockk.every +import io.mockk.mockk +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.core.IsInstanceOf +import org.junit.jupiter.api.Test +import org.slf4j.Logger +import org.slf4j.event.Level + +class LoggerManagerTest { + @Test + fun `should create logger successfully when customLoggers are null`() { + val mockSlf4jLogger = mockk(relaxed = true) + val mockFactory = { _: Class<*> -> mockSlf4jLogger } + val manager = LoggerManager(loggerFactory = mockFactory) + + val testLogConfig = LogConfig("test-instance-id", "test-user-id", customLoggers = null) + + val logger = manager.getLogger(testLogConfig, String::class.java) + + assertThat(logger, IsInstanceOf.instanceOf(CompositeLogger::class.java)) + } + + @Test + fun `should create CompositeLogger when custom loggers are provided`() { + val mockSlf4jLogger = mockk(relaxed = true) + val mockFactory = { _: Class<*> -> mockSlf4jLogger } + val manager = LoggerManager(loggerFactory = mockFactory) + + val customLogger = mockk(relaxed = true) + every { customLogger.name } returns "TestCustomLogger" + + val testLogConfig = LogConfig( + pnInstanceId = "test-instance-id", + userId = "test-user-id", + customLoggers = listOf(customLogger) + ) + + val logger = manager.getLogger(testLogConfig, String::class.java) + + assertThat(logger, IsInstanceOf.instanceOf(CompositeLogger::class.java)) + } + + @Test + fun `should handle logger creation failure gracefully`() { + val mockFactory = { _: Class<*> -> throw RuntimeException("SLF4J failed!") } + val manager = LoggerManager(loggerFactory = mockFactory) + + val testLogConfig = LogConfig("test-instance-id", "test-user-id") + + // Should not throw exception + val logger = manager.getLogger(testLogConfig, String::class.java) + + // Verify it's not null and logging works + assertThat(logger, IsInstanceOf.instanceOf(PNLogger::class.java)) + + // Should not crash when logging + logger.error( + LogMessage( + message = LogMessageContent.Text("test error"), + type = LogMessageType.ERROR, + location = "test", + pubNubId = testLogConfig.pnInstanceId, + logLevel = Level.ERROR + ) + ) + } + + @Test + fun `should return fallback logger when SLF4J creation fails`() { + val mockFactory = { _: Class<*> -> throw RuntimeException("SLF4J failed!") } + val manager = LoggerManager(loggerFactory = mockFactory) + + val testLogConfig = LogConfig("test-instance-id", "test-user-id") + val logger = manager.getLogger(testLogConfig, String::class.java) + + // Should still be able to log without crashing + logger.info( + LogMessage( + message = LogMessageContent.Text("test info"), + type = LogMessageType.TEXT, + location = "test", + pubNubId = "test", + logLevel = Level.INFO + ) + ) + } + + @Test + fun `should handle empty custom loggers list`() { + val mockSlf4jLogger = mockk(relaxed = true) + val mockFactory = { _: Class<*> -> mockSlf4jLogger } + val manager = LoggerManager(loggerFactory = mockFactory) + + val testLogConfig = LogConfig( + pnInstanceId = "test-instance-id", + userId = "test-user-id", + customLoggers = emptyList() + ) + + val logger = manager.getLogger(testLogConfig, String::class.java) + + // Should create ToPortalLogger, not CompositeLogger + assertThat(logger, IsInstanceOf.instanceOf(CompositeLogger::class.java)) + } + + @Test + fun `should handle null custom loggers`() { + val mockSlf4jLogger = mockk(relaxed = true) + val mockFactory = { _: Class<*> -> mockSlf4jLogger } + val manager = LoggerManager(loggerFactory = mockFactory) + + val pnInstanceId = "test-instance-id" + val testLogConfig = LogConfig( + pnInstanceId = pnInstanceId, + userId = "test-user-id", + customLoggers = null + ) + + val logger = manager.getLogger(testLogConfig, String::class.java) + + // Should create ToPortalLogger, not CompositeLogger + assertThat(logger, IsInstanceOf.instanceOf(CompositeLogger::class.java)) + } + + @Test + fun `should use default instance correctly`() { + val manager = LoggerManager.instance + val testLogConfig = LogConfig("test-instance-id", "test-user-id") + + val logger = manager.getLogger(testLogConfig, String::class.java) + + assertThat(logger, IsInstanceOf.instanceOf(PNLogger::class.java)) + } + + @Test + fun `should create different loggers for different classes`() { + val mockSlf4jLogger1 = mockk(relaxed = true) + val mockSlf4jLogger2 = mockk(relaxed = true) + + val mockFactory = { clazz: Class<*> -> + when (clazz) { + String::class.java -> mockSlf4jLogger1 + Int::class.java -> mockSlf4jLogger2 + else -> mockk(relaxed = true) + } + } + + val manager = LoggerManager(loggerFactory = mockFactory) + val testLogConfig = LogConfig("test-instance-id", "test-user-id") + + val logger1 = manager.getLogger(testLogConfig, String::class.java) + val logger2 = manager.getLogger(testLogConfig, Int::class.java) + + // Both should be ExtendedLogger but potentially different instances + assertThat(logger1, IsInstanceOf.instanceOf(PNLogger::class.java)) + assertThat(logger2, IsInstanceOf.instanceOf(PNLogger::class.java)) + } + + @Test + fun `should handle multiple custom loggers`() { + val mockSlf4jLogger = mockk(relaxed = true) + val mockFactory = { _: Class<*> -> mockSlf4jLogger } + val manager = LoggerManager(loggerFactory = mockFactory) + + val customLogger1 = mockk(relaxed = true) + val customLogger2 = mockk(relaxed = true) + every { customLogger1.name } returns "CustomLogger1" + every { customLogger2.name } returns "CustomLogger2" + + val testLogConfig = LogConfig( + pnInstanceId = "test-instance-id", + userId = "test-user-id", + customLoggers = listOf(customLogger1, customLogger2) + ) + + val logger = manager.getLogger(testLogConfig, String::class.java) + + assertThat(logger, IsInstanceOf.instanceOf(CompositeLogger::class.java)) + } + + @Test + fun `should handle ToPortalLogger creation failure and fallback to basic SLF4J`() { + var callCount = 0 + val mockFactory = { _: Class<*> -> + callCount++ + if (callCount == 1) { + throw RuntimeException("First call failed") + } else { + mockk(relaxed = true) + } + } + + val manager = LoggerManager(loggerFactory = mockFactory) + val testLogConfig = LogConfig("test-instance-id", "test-user-id") + + val logger = manager.getLogger(testLogConfig, String::class.java) + + // Should still get a working logger (fallback) + assertThat(logger, IsInstanceOf.instanceOf(PNLogger::class.java)) + + // Should be able to log without crashing + logger.warn( + LogMessage( + message = LogMessageContent.Text("test warning"), + type = LogMessageType.TEXT, + location = "test", + pubNubId = "test", + logLevel = Level.WARN + ) + ) + } +} diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/logging/networkLogging/LogMessageFormatterTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/logging/networkLogging/LogMessageFormatterTest.kt new file mode 100644 index 0000000000..779d65743e --- /dev/null +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/logging/networkLogging/LogMessageFormatterTest.kt @@ -0,0 +1,262 @@ +package com.pubnub.internal.logging.networkLogging + +import com.pubnub.api.logging.ErrorDetails +import com.pubnub.api.logging.HttpMethod +import com.pubnub.api.logging.LogMessage +import com.pubnub.api.logging.LogMessageContent +import com.pubnub.api.logging.LogMessageType +import com.pubnub.api.logging.NetworkLog +import com.pubnub.api.logging.NetworkRequestMessage +import com.pubnub.api.logging.NetworkResponseMessage +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test +import org.slf4j.event.Level + +class LogMessageFormatterTest { + @Test + fun `should format text message content correctly`() { + val textContent = LogMessageContent.Text("Simple text message") + + val result = LogMessageFormatter.formatMessageContent(textContent) + + assertEquals("Simple text message", result) + } + + @Test + fun `should format object message content as pretty JSON`() { + val testObject = mapOf( + "key1" to "value1", + "key2" to 42, + "key3" to listOf("item1", "item2") + ) + val objectContent = LogMessageContent.Object(testObject) + + val result = LogMessageFormatter.formatMessageContent(objectContent) + + // Should be pretty-printed JSON + assertTrue(result.contains("\"key1\": \"value1\"")) + assertTrue(result.contains("\"key2\": 42")) + assertTrue(result.contains("\"key3\": [")) + assertTrue(result.contains(" ")) // Should have indentation + } + + @Test + fun `should format error message content with stack trace`() { + val errorDetails = ErrorDetails( + type = "RuntimeException", + message = "Something went wrong", + stack = listOf( + "at com.example.Test.method1(Test.java:10)", + "at com.example.Test.method2(Test.java:20)" + ) + ) + val errorContent = LogMessageContent.Error(errorDetails) + + val result = LogMessageFormatter.formatMessageContent(errorContent) + + assertTrue(result.contains("Error(type=RuntimeException")) + assertTrue(result.contains("message=Something went wrong")) + assertTrue(result.contains("at com.example.Test.method1(Test.java:10)")) + assertTrue(result.contains("at com.example.Test.method2(Test.java:20)")) + } + + @Test + fun `should format error message content without stack trace`() { + val errorDetails = ErrorDetails( + type = "IOException", + message = "Network error", + stack = null + ) + val errorContent = LogMessageContent.Error(errorDetails) + + val result = LogMessageFormatter.formatMessageContent(errorContent) + + assertTrue(result.contains("Error(type=IOException")) + assertTrue(result.contains("message=Network error")) + assertTrue(result.contains("stack=null")) + } + + @Test + fun `should format network request message content as JSON`() { + val networkRequest = NetworkRequestMessage( + origin = "https://ps.pndsn.com", + path = "/v2/subscribe/demo/my-channel/0", + query = mapOf("uuid" to "test-uuid"), + method = HttpMethod.GET, + headers = mapOf("User-Agent" to "test-agent"), + formData = null, + body = """{"message": "hello"}""", + timeout = 5000, + identifier = "req-123" + ) + val requestLog = NetworkLog.Request(networkRequest, canceled = false, failed = false) + val requestContent = LogMessageContent.NetworkRequest(requestLog) + + val result = LogMessageFormatter.formatMessageContent(requestContent) + + assertTrue(result.startsWith("NetworkRequest:")) + assertTrue(result.contains("\"origin\": \"https://ps.pndsn.com\"")) + assertTrue(result.contains("\"path\": \"/v2/subscribe/demo/my-channel/0\"")) + assertTrue(result.contains("\"method\": \"GET\"")) + assertTrue(result.contains("\"uuid\": \"test-uuid\"")) + assertTrue(result.contains("\"User-Agent\": \"test-agent\"")) + assertTrue(result.contains("req-123")) + assertTrue(result.contains(" ")) // Should have pretty printing + } + + @Test + fun `should format network response message content as JSON`() { + val networkResponse = NetworkResponseMessage( + url = "https://ps.pndsn.com/v2/subscribe/demo/my-channel/0", + status = 200, + headers = mapOf("Content-Type" to "application/json"), + body = """{"status": 200, "message": "OK"}""" + ) + val responseLog = NetworkLog.Response(networkResponse) + val responseContent = LogMessageContent.NetworkResponse(responseLog) + + val result = LogMessageFormatter.formatMessageContent(responseContent) + + assertTrue(result.startsWith("NetworkResponse:")) + assertTrue(result.contains("\"url\": \"https://ps.pndsn.com/v2/subscribe/demo/my-channel/0\"")) + assertTrue(result.contains("\"status\": 200")) + assertTrue(result.contains("\"Content-Type\": \"application/json\"")) + assertTrue(result.contains("\"body\": \"{\\\"status\\\": 200")) + assertTrue(result.contains(" ")) // Should have pretty printing + } + + @Test + fun `should handle unknown message content types gracefully`() { + // Test the else branch by using a content type that doesn't match the when cases + val textContent = LogMessageContent.Text("test") + + val result = LogMessageFormatter.formatMessageContent(textContent) + + // Should return the text message + assertEquals("test", result) + } + + @Test + fun `simplified extension function should format complete log message`() { + val logMessage = LogMessage( + message = LogMessageContent.Text("This is a test message"), + details = "Additional context information", + type = LogMessageType.TEXT, + location = "TestClass.testMethod", + pubNubId = "test-instance-123", + logLevel = Level.INFO + ) + + val result = logMessage.simplified() + + assertTrue(result.contains("pnInstanceId: test-instance-123")) + assertTrue(result.contains("location: TestClass.testMethod")) + assertTrue(result.contains("details: Additional context information")) + assertTrue(result.contains("This is a test message")) + } + + @Test + fun `simplified extension function should handle null details`() { + val logMessage = LogMessage( + message = LogMessageContent.Object(mapOf("key" to "value")), + details = null, + type = LogMessageType.OBJECT, + location = "AnotherClass.anotherMethod", + pubNubId = "test-instance-456", + logLevel = Level.DEBUG + ) + + val result = logMessage.simplified() + + assertTrue(result.contains("pnInstanceId: test-instance-456")) + assertTrue(result.contains("location: AnotherClass.anotherMethod")) + assertTrue(result.contains("details: ")) // Should show empty string for null details + assertTrue(result.contains("\"key\": \"value\"")) + } + + @Test + fun `simplified extension function should format complex network request`() { + val networkRequest = NetworkRequestMessage( + origin = "https://ps.pndsn.com", + path = "/publish/demo/my-channel/0", + query = mapOf("pnsdk" to "kotlin/1.0.0", "uuid" to "user-123"), + method = HttpMethod.POST, + headers = mapOf( + "Content-Type" to "application/json", + "Authorization" to "Bearer token123" + ), + formData = null, + body = """{"text": "Hello World!", "meta": {"timestamp": 1234567890}}""", + timeout = 10000, + identifier = "publish-req-789" + ) + val requestLog = NetworkLog.Request(networkRequest, canceled = false, failed = false) + val logMessage = LogMessage( + message = LogMessageContent.NetworkRequest(requestLog), + details = "Publishing message to channel", + type = LogMessageType.NETWORK_REQUEST, + location = "PublishEndpoint", + pubNubId = "publish-instance", + logLevel = Level.DEBUG + ) + + val result = logMessage.simplified() + + assertTrue(result.contains("pnInstanceId: publish-instance")) + assertTrue(result.contains("location: PublishEndpoint")) + assertTrue(result.contains("details: Publishing message to channel")) + assertTrue(result.contains("NetworkRequest:")) + assertTrue(result.contains("\"method\": \"POST\"")) + assertTrue(result.contains("\"Authorization\": \"Bearer token123\"")) + assertTrue(result.contains("Hello World!")) + assertTrue(result.contains("publish-req-789")) + } + + @Test + fun `should handle complex nested objects in formatting`() { + val complexObject = mapOf( + "simpleString" to "value", + "number" to 42, + "boolean" to true, + "nestedObject" to mapOf( + "innerKey" to "innerValue", + "innerList" to listOf(1, 2, 3) + ), + "arrayOfObjects" to listOf( + mapOf("id" to 1, "name" to "item1"), + mapOf("id" to 2, "name" to "item2") + ) + ) + val objectContent = LogMessageContent.Object(complexObject) + + val result = LogMessageFormatter.formatMessageContent(objectContent) + + // Verify all elements are present and properly formatted + assertTrue(result.contains("\"simpleString\": \"value\"")) + assertTrue(result.contains("\"number\": 42")) + assertTrue(result.contains("\"boolean\": true")) + assertTrue(result.contains("\"innerKey\": \"innerValue\"")) + assertTrue(result.contains("\"innerList\": [")) + assertTrue(result.contains("\"arrayOfObjects\": [")) + assertTrue(result.contains("\"name\": \"item1\"")) + // Should be pretty-printed with proper indentation + assertTrue(result.contains(" ")) + } + + @Test + fun `should format empty collections correctly`() { + val objectWithEmptyCollections: Map = mapOf( + "emptyList" to emptyList(), + "emptyMap" to emptyMap(), + "emptyString" to "" + ) + val objectContent = LogMessageContent.Object(objectWithEmptyCollections) + + val result = LogMessageFormatter.formatMessageContent(objectContent) + + assertTrue(result.contains("\"emptyList\": []")) + assertTrue(result.contains("\"emptyMap\": {}")) + assertTrue(result.contains("\"emptyString\": \"\"")) + } +} diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/managers/MapperManagerTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/managers/MapperManagerTest.kt index ce31bb4aa2..2c3dca8df1 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/managers/MapperManagerTest.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/managers/MapperManagerTest.kt @@ -1,6 +1,7 @@ package com.pubnub.internal.managers import com.pubnub.api.PubNubException +import com.pubnub.api.logging.LogConfig import com.pubnub.api.models.consumer.objects.channel.PNChannelMetadata import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertNotNull @@ -8,10 +9,12 @@ import org.junit.jupiter.api.Assertions.assertNull import org.junit.jupiter.api.Test internal class MapperManagerTest { + val logConfig = LogConfig("testPnInstanceId", "testUserId") + @Test @Throws(PubNubException::class) fun toJson_anonymousList() { - val mapperManager = MapperManager() + val mapperManager = MapperManager(logConfig) val expected = "[1,2,3]" val anonList: List = object : ArrayList() { @@ -34,7 +37,7 @@ internal class MapperManagerTest { @Test @Throws(PubNubException::class) fun toJson_anonymousMap() { - val mapperManager = MapperManager() + val mapperManager = MapperManager(logConfig) val expected = "{\"city\":\"Toronto\"}" val anonMap: HashMap = object : HashMap() { @@ -53,7 +56,7 @@ internal class MapperManagerTest { @Test @Throws(PubNubException::class) fun toJson_anonymousSet() { - val mapperManager = MapperManager() + val mapperManager = MapperManager(logConfig) val expected = "[1,2,3]" val anonSet: Set = object : HashSet() { @@ -75,7 +78,7 @@ internal class MapperManagerTest { @Test fun fromJson_numbers() { - val mapperManager = MapperManager() + val mapperManager = MapperManager(logConfig) val map = mapOf( "a" to 12345678, "b" to 1.2313, @@ -100,7 +103,7 @@ internal class MapperManagerTest { @Test fun fromJson_optionalsAndNulls() { - val mapperManager = MapperManager() + val mapperManager = MapperManager(logConfig) val input = """ { "id" : "myId", "name": null, "description": "myDescription", "eTag": "myEtag", "custom": { "a" : "b" } } """.trimIndent() diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/presence/PresenceTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/presence/PresenceTest.kt index bce30da48f..4b554f3352 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/presence/PresenceTest.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/presence/PresenceTest.kt @@ -1,6 +1,7 @@ package com.pubnub.internal.presence import com.pubnub.api.enums.PNHeartbeatNotificationOptions +import com.pubnub.api.logging.LogConfig import com.pubnub.contract.subscribe.eventEngine.state.TestSinkSource import com.pubnub.internal.eventengine.EventEngineConf import com.pubnub.internal.eventengine.QueueEventEngineConf @@ -33,6 +34,7 @@ private const val CHANNEL_GROUPS_01 = "channelGroups01" internal class PresenceTest { private val listenerManager: ListenerManager = mockk() private val executorService: ScheduledExecutorService = mockk() + private val logConfig: LogConfig = LogConfig(pnInstanceId = "testInstanceId", userId = "testUserId") companion object { @JvmStatic @@ -162,7 +164,9 @@ internal class PresenceTest { fun `should call heartbeat when joining channels with heartbeat interval 0`() { // given val heartbeatProviderMock: HeartbeatProvider = mockk() - every { heartbeatProviderMock.getHeartbeatRemoteAction(any(), any(), any()) } returns successfulRemoteAction(true) + every { heartbeatProviderMock.getHeartbeatRemoteAction(any(), any(), any()) } returns successfulRemoteAction( + true + ) val presence = Presence.create( @@ -182,7 +186,9 @@ internal class PresenceTest { fun `should not call heartbeat when joining empty channels with heartbeat interval 0`() { // given val heartbeatProviderMock: HeartbeatProvider = mockk() - every { heartbeatProviderMock.getHeartbeatRemoteAction(any(), any(), any()) } returns successfulRemoteAction(true) + every { heartbeatProviderMock.getHeartbeatRemoteAction(any(), any(), any()) } returns successfulRemoteAction( + true + ) val presence = Presence.create( @@ -207,6 +213,7 @@ internal class PresenceTest { suppressLeaveEvents: Boolean = false, leaveProvider: LeaveProvider = LeaveProvider { _, _ -> successfulRemoteAction(true) }, heartbeatProvider: HeartbeatProvider = HeartbeatProvider { _, _, _ -> successfulRemoteAction(true) }, + logConfig: LogConfig = LogConfig(pnInstanceId = "testInstanceId", userId = "testUserId"), ) = create( heartbeatProvider = heartbeatProvider, leaveProvider = leaveProvider, @@ -218,5 +225,6 @@ internal class PresenceTest { presenceData = presenceData, sendStateWithHeartbeat = true, executorService = executorService, + logConfig = logConfig, ) } diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/presence/eventengine/effect/HeartbeatEffectTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/presence/eventengine/effect/HeartbeatEffectTest.kt index 3bd0d966d1..8dd7c8cff7 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/presence/eventengine/effect/HeartbeatEffectTest.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/presence/eventengine/effect/HeartbeatEffectTest.kt @@ -2,6 +2,7 @@ package com.pubnub.internal.presence.eventengine.effect import com.pubnub.api.PubNubException import com.pubnub.api.enums.PNHeartbeatNotificationOptions +import com.pubnub.api.logging.LogConfig import com.pubnub.internal.presence.eventengine.event.PresenceEvent import com.pubnub.internal.subscribe.eventengine.effect.StatusConsumer import com.pubnub.internal.subscribe.eventengine.effect.TestEventSink @@ -24,6 +25,7 @@ class HeartbeatEffectTest { private val reason = PubNubException("Unknown error") private val heartbeatNotificationOptions: PNHeartbeatNotificationOptions = PNHeartbeatNotificationOptions.ALL private val statusConsumer: StatusConsumer = mockk() + private val logConfig: LogConfig = LogConfig(pnInstanceId = "testInstanceId", userId = "testUserId") companion object { @JvmStatic @@ -48,7 +50,7 @@ class HeartbeatEffectTest { // given every { statusConsumer.announce(any()) } returns Unit val heartbeatEffect = - HeartbeatEffect(successfulRemoteAction(true), eventSink, heartbeatNotificationOptions, statusConsumer) + HeartbeatEffect(successfulRemoteAction(true), eventSink, heartbeatNotificationOptions, statusConsumer, logConfig) // when heartbeatEffect.runEffect() @@ -68,7 +70,7 @@ class HeartbeatEffectTest { // given every { statusConsumer.announce(any()) } returns Unit val heartbeatEffect = - HeartbeatEffect(failingRemoteAction(reason), eventSink, heartbeatNotificationOptions, statusConsumer) + HeartbeatEffect(failingRemoteAction(reason), eventSink, heartbeatNotificationOptions, statusConsumer, logConfig) // when heartbeatEffect.runEffect() @@ -91,7 +93,7 @@ class HeartbeatEffectTest { // given val heartbeatNotificationOptions: PNHeartbeatNotificationOptions = pnHeartbeatNotificationOptions val heartbeatEffect = - HeartbeatEffect(successfulRemoteAction(true), eventSink, heartbeatNotificationOptions, statusConsumer) + HeartbeatEffect(successfulRemoteAction(true), eventSink, heartbeatNotificationOptions, statusConsumer, logConfig) // when heartbeatEffect.runEffect() @@ -119,7 +121,7 @@ class HeartbeatEffectTest { // given val heartbeatNotificationOptions: PNHeartbeatNotificationOptions = pnHeartbeatNotificationOptions val heartbeatEffect = - HeartbeatEffect(failingRemoteAction(reason), eventSink, heartbeatNotificationOptions, statusConsumer) + HeartbeatEffect(failingRemoteAction(reason), eventSink, heartbeatNotificationOptions, statusConsumer, logConfig) // when heartbeatEffect.runEffect() diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/presence/eventengine/effect/LeaveEffectTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/presence/eventengine/effect/LeaveEffectTest.kt index 3315c4e2ee..5bdcf76fd8 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/presence/eventengine/effect/LeaveEffectTest.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/presence/eventengine/effect/LeaveEffectTest.kt @@ -1,6 +1,7 @@ package com.pubnub.internal.presence.eventengine.effect import com.pubnub.api.endpoints.remoteaction.RemoteAction +import com.pubnub.api.logging.LogConfig import io.mockk.Runs import io.mockk.every import io.mockk.just @@ -10,11 +11,12 @@ import org.junit.jupiter.api.Test class LeaveEffectTest { private val leaveRemoteAction: RemoteAction = mockk() + private val logConfig: LogConfig = LogConfig(pnInstanceId = "testInstanceId", userId = "testUserId") @Test fun `when runEffect is executed should call leaveRemoteAction`() { // given - val leaveEffect = LeaveEffect(leaveRemoteAction) + val leaveEffect = LeaveEffect(leaveRemoteAction, logConfig) every { leaveRemoteAction.async(any()) } just Runs // when diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/presence/eventengine/effect/PresenceEffectFactoryTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/presence/eventengine/effect/PresenceEffectFactoryTest.kt index 248cf16bfd..50a5b22a13 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/presence/eventengine/effect/PresenceEffectFactoryTest.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/presence/eventengine/effect/PresenceEffectFactoryTest.kt @@ -2,6 +2,7 @@ package com.pubnub.internal.presence.eventengine.effect import com.pubnub.api.endpoints.remoteaction.RemoteAction import com.pubnub.api.enums.PNHeartbeatNotificationOptions +import com.pubnub.api.logging.LogConfig import com.pubnub.internal.eventengine.Sink import com.pubnub.internal.presence.eventengine.data.PresenceData import com.pubnub.internal.presence.eventengine.effect.effectprovider.HeartbeatProvider @@ -36,6 +37,7 @@ class PresenceEffectFactoryTest { private val heartbeatNotificationOptions: PNHeartbeatNotificationOptions = mockk() private val statusConsumer: StatusConsumer = mockk() private val presenceData = PresenceData() + private val logConfig: LogConfig = LogConfig(pnInstanceId = "testInstanceId", userId = "testUserId") @BeforeEach fun setUp() { @@ -52,6 +54,7 @@ class PresenceEffectFactoryTest { statusConsumer, presenceData, true, + logConfig, ) } @@ -136,6 +139,7 @@ class PresenceEffectFactoryTest { statusConsumer, presenceData, false, + logConfig ).create(effectInvocation) // then @@ -181,6 +185,7 @@ class PresenceEffectFactoryTest { statusConsumer, PresenceData(), true, + logConfig ) val effectInvocation = PresenceEffectInvocation.Leave(channels, channelGroups) every { diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/presence/eventengine/effect/WaitEffectTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/presence/eventengine/effect/WaitEffectTest.kt index a279cde475..5accc3bec2 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/presence/eventengine/effect/WaitEffectTest.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/presence/eventengine/effect/WaitEffectTest.kt @@ -1,5 +1,6 @@ package com.pubnub.internal.presence.eventengine.effect +import com.pubnub.api.logging.LogConfig import com.pubnub.internal.presence.eventengine.event.PresenceEvent import com.pubnub.internal.subscribe.eventengine.effect.TestEventSink import org.awaitility.Awaitility @@ -14,6 +15,7 @@ import kotlin.time.Duration.Companion.milliseconds class WaitEffectTest { private val heartbeatInterval = 1.milliseconds private val presenceEventSink = TestEventSink() + private val logConfig: LogConfig = LogConfig(pnInstanceId = "testInstanceId", userId = "testUserId") companion object { private val executorService: ScheduledExecutorService = Executors.newScheduledThreadPool(10) @@ -28,7 +30,7 @@ class WaitEffectTest { @Test fun `should deliver TimesUp event when WaitEffect finishes successfully`() { // given - val waitEffect = WaitEffect(heartbeatInterval, presenceEventSink, executorService) + val waitEffect = WaitEffect(heartbeatInterval, presenceEventSink, executorService, logConfig) // when waitEffect.runEffect() @@ -46,7 +48,7 @@ class WaitEffectTest { @Test fun `should not deliver TimesUp event when cancelled on time`() { // given - val waitEffect = WaitEffect(20.milliseconds, presenceEventSink, executorService) + val waitEffect = WaitEffect(20.milliseconds, presenceEventSink, executorService, logConfig) // when waitEffect.runEffect() @@ -67,7 +69,7 @@ class WaitEffectTest { @Test fun `should not deliver TimesUp event when cancelled before runEffect`() { // given - val waitEffect = WaitEffect(heartbeatInterval, presenceEventSink, executorService) + val waitEffect = WaitEffect(heartbeatInterval, presenceEventSink, executorService, logConfig) // when waitEffect.cancel() diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/retry/RetryableCallbackTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/retry/RetryableCallbackTest.kt index 13acbf1ab5..5bda701b8b 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/retry/RetryableCallbackTest.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/retry/RetryableCallbackTest.kt @@ -1,5 +1,6 @@ package com.pubnub.internal.retry +import com.pubnub.api.logging.LogConfig import com.pubnub.api.retry.RetryConfiguration import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.test.listen @@ -26,6 +27,7 @@ class RetryableCallbackTest { private lateinit var mockResponse: Response private var onFinalResponseCalled = false private var onFinalFailureCalled = false + private val testLogConfig = LogConfig("test-instance-id", "test-user-id") @BeforeEach fun setUp() { @@ -55,6 +57,7 @@ class RetryableCallbackTest { call = mockCall, isEndpointRetryable = true, executorService = executorService, + testLogConfig, ) { override fun onFinalResponse( call: Call, diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/retry/RetryableRestCallerTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/retry/RetryableRestCallerTest.kt index c802e3d138..ce56fef9d7 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/retry/RetryableRestCallerTest.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/retry/RetryableRestCallerTest.kt @@ -2,6 +2,7 @@ package com.pubnub.internal.retry import com.pubnub.api.PubNubError import com.pubnub.api.PubNubException +import com.pubnub.api.logging.LogConfig import com.pubnub.api.retry.RetryConfiguration import com.pubnub.api.retry.RetryableEndpointGroup import com.pubnub.internal.models.server.FetchMessagesEnvelope @@ -22,12 +23,14 @@ private const val RETRY_AFTER_HEADER_NAME = "Retry-After" private const val RETRY_AFTER_VALUE = "3" class RetryableRestCallerTest { + private val testLogConfig = LogConfig("test-instance-id", "test-user-id") + private fun getRetryableRestCaller( retryConfiguration: RetryConfiguration, isEndpointRetryable: Boolean = true, endpointGroupName: RetryableEndpointGroup = RetryableEndpointGroup.MESSAGE_PERSISTENCE, ): RetryableRestCaller { - return RetryableRestCaller(retryConfiguration, endpointGroupName, isEndpointRetryable) + return RetryableRestCaller(retryConfiguration, endpointGroupName, isEndpointRetryable, testLogConfig) } @Test diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/subscribe/eventengine/effect/EmitMessagesEffectTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/subscribe/eventengine/effect/EmitMessagesEffectTest.kt index cd3a7655ae..f28a22d0ed 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/subscribe/eventengine/effect/EmitMessagesEffectTest.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/subscribe/eventengine/effect/EmitMessagesEffectTest.kt @@ -1,6 +1,7 @@ package com.pubnub.internal.subscribe.eventengine.effect import com.google.gson.JsonPrimitive +import com.pubnub.api.logging.LogConfig import com.pubnub.api.models.consumer.files.PNDownloadableFile import com.pubnub.api.models.consumer.message_actions.PNMessageAction import com.pubnub.api.models.consumer.pubsub.BasePubSubResult @@ -26,12 +27,13 @@ class EmitMessagesEffectTest { private val message = "Message1" private val messageActionType = "reaction" private val objectEventType = "membership" + private val logConfig: LogConfig = LogConfig(pnInstanceId = "testInstanceId", userId = "testUserId") @Test fun `should announce PNMessageResult when PNMessageResult exist in messages`() { // given val messages: List = listOf(PNMessageResult(createBasePubSubResult(), JsonPrimitive(message))) - val emitMessagesEffect = EmitMessagesEffect(messagesConsumer, messages) + val emitMessagesEffect = EmitMessagesEffect(messagesConsumer, messages, logConfig) val pnEventCapture = slot() every { messagesConsumer.announce(capture(pnEventCapture)) } returns Unit @@ -47,7 +49,7 @@ class EmitMessagesEffectTest { fun `should announce PNSignalResult when PNSignalResult exist in messages`() { // given val messages: List = listOf(PNSignalResult(createBasePubSubResult(), JsonPrimitive(message))) - val emitMessagesEffect = EmitMessagesEffect(messagesConsumer, messages) + val emitMessagesEffect = EmitMessagesEffect(messagesConsumer, messages, logConfig) val pnEventCapture = slot() every { messagesConsumer.announce(capture(pnEventCapture)) } returns Unit @@ -63,7 +65,7 @@ class EmitMessagesEffectTest { fun `should announce PNFileEventResult when PNFileEventResult exist in messages`() { // given val messages: List = listOf(createPnFileEventResult(message)) - val emitMessagesEffect = EmitMessagesEffect(messagesConsumer, messages) + val emitMessagesEffect = EmitMessagesEffect(messagesConsumer, messages, logConfig) val pnEventCapture = slot() every { messagesConsumer.announce(capture(pnEventCapture)) } returns Unit @@ -79,7 +81,7 @@ class EmitMessagesEffectTest { fun `should announce PNMessageActionResult when PNMessageActionResult exist in messages`() { // given val messages: List = listOf(createPnMessageActionResult(messageActionType)) - val emitMessagesEffect = EmitMessagesEffect(messagesConsumer, messages) + val emitMessagesEffect = EmitMessagesEffect(messagesConsumer, messages, logConfig) val pnEventCapture = slot() every { messagesConsumer.announce(capture(pnEventCapture)) } returns Unit @@ -95,7 +97,7 @@ class EmitMessagesEffectTest { fun `should announce PNObjectEventResult when PNObjectEventResult exist in messages`() { // given val messages: List = listOf(createPnObjectEventResult(objectEventType)) - val emitMessagesEffect = EmitMessagesEffect(messagesConsumer, messages) + val emitMessagesEffect = EmitMessagesEffect(messagesConsumer, messages, logConfig) val pnEventCapture = slot() every { messagesConsumer.announce(capture(pnEventCapture)) } returns Unit @@ -128,7 +130,7 @@ class EmitMessagesEffectTest { pnMessageActionResult, pnObjectEventResult, ) - val emitMessagesEffect = EmitMessagesEffect(messagesConsumer, listOfDifferentMessages) + val emitMessagesEffect = EmitMessagesEffect(messagesConsumer, listOfDifferentMessages, logConfig) // when emitMessagesEffect.runEffect() diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/subscribe/eventengine/effect/EmitStatusEffectTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/subscribe/eventengine/effect/EmitStatusEffectTest.kt index bba52937d5..c7014d6a5a 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/subscribe/eventengine/effect/EmitStatusEffectTest.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/subscribe/eventengine/effect/EmitStatusEffectTest.kt @@ -1,5 +1,6 @@ package com.pubnub.internal.subscribe.eventengine.effect +import com.pubnub.api.logging.LogConfig import com.pubnub.api.models.consumer.PNStatus import io.mockk.every import io.mockk.mockk @@ -11,11 +12,12 @@ import org.junit.jupiter.api.Test class EmitStatusEffectTest { private val statusConsumer: StatusConsumer = mockk() val status: PNStatus = mockk() + private val logConfig: LogConfig = LogConfig(pnInstanceId = "testInstanceId", userId = "testUserId") @Test fun `should announce status when status provided`() { // given - val emitStatusEffect = EmitStatusEffect(statusConsumer, status) + val emitStatusEffect = EmitStatusEffect(statusConsumer, status, logConfig) val pnStatusCapture = slot() every { statusConsumer.announce(capture(pnStatusCapture)) } returns Unit diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/subscribe/eventengine/effect/HandshakeEffectTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/subscribe/eventengine/effect/HandshakeEffectTest.kt index b06620f8c7..380285e8b5 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/subscribe/eventengine/effect/HandshakeEffectTest.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/subscribe/eventengine/effect/HandshakeEffectTest.kt @@ -2,6 +2,7 @@ package com.pubnub.internal.subscribe.eventengine.effect import com.pubnub.api.PubNubException import com.pubnub.api.endpoints.remoteaction.RemoteAction +import com.pubnub.api.logging.LogConfig import com.pubnub.api.v2.callbacks.Result import com.pubnub.internal.eventengine.Sink import com.pubnub.internal.subscribe.eventengine.event.SubscribeEvent @@ -20,11 +21,12 @@ class HandshakeEffectTest { private val subscribeEventSink = TestEventSink() private val subscriptionCursor = SubscriptionCursor(1337L, "1337") private val reason = PubNubException("Unknown error") + private val logConfig: LogConfig = LogConfig(pnInstanceId = "testInstanceId", userId = "testUserId") @Test fun `should deliver HandshakeSuccess event when HandshakeEffect succeeded`() { // given - val handshakeEffect = HandshakeEffect(successfulRemoteAction(subscriptionCursor), subscribeEventSink) + val handshakeEffect = HandshakeEffect(successfulRemoteAction(subscriptionCursor), subscribeEventSink, logConfig) // when handshakeEffect.runEffect() @@ -42,7 +44,7 @@ class HandshakeEffectTest { @Test fun `should deliver HandshakeFailure event when HandshakeEffect failed`() { // given - val handshakeEffect = HandshakeEffect(failingRemoteAction(reason), subscribeEventSink) + val handshakeEffect = HandshakeEffect(failingRemoteAction(reason), subscribeEventSink, logConfig) // when handshakeEffect.runEffect() @@ -61,7 +63,7 @@ class HandshakeEffectTest { fun `should cancel remoteAction when cancel effect`() { // given val remoteAction: RemoteAction = spyk() - val handshakeEffect = HandshakeEffect(remoteAction, subscribeEventSink) + val handshakeEffect = HandshakeEffect(remoteAction, subscribeEventSink, logConfig) // when handshakeEffect.cancel() diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/subscribe/eventengine/effect/ReceiveMessagesEffectTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/subscribe/eventengine/effect/ReceiveMessagesEffectTest.kt index 0b373cd6a2..09de1af4e1 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/subscribe/eventengine/effect/ReceiveMessagesEffectTest.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/subscribe/eventengine/effect/ReceiveMessagesEffectTest.kt @@ -3,6 +3,7 @@ package com.pubnub.internal.subscribe.eventengine.effect import com.google.gson.JsonPrimitive import com.pubnub.api.PubNubException import com.pubnub.api.endpoints.remoteaction.RemoteAction +import com.pubnub.api.logging.LogConfig import com.pubnub.api.models.consumer.pubsub.BasePubSubResult import com.pubnub.api.models.consumer.pubsub.PNEvent import com.pubnub.api.models.consumer.pubsub.PNMessageResult @@ -22,12 +23,13 @@ class ReceiveMessagesEffectTest { private val messages: List = createPNMessageResultList() private val receiveMessageResult = ReceiveMessagesResult(messages, subscriptionCursor) private val reason = PubNubException("Test") + private val logConfig: LogConfig = LogConfig(pnInstanceId = "testInstanceId", userId = "testUserId") @Test fun `should deliver ReceiveSuccess event when ReceiveMessagesEffect succeeded `() { // given val receiveMessagesEffect = - ReceiveMessagesEffect(successfulRemoteAction(receiveMessageResult), subscribeEventSink) + ReceiveMessagesEffect(successfulRemoteAction(receiveMessageResult), subscribeEventSink, logConfig) // when receiveMessagesEffect.runEffect() @@ -48,7 +50,7 @@ class ReceiveMessagesEffectTest { @Test fun `should deliver ReceiveFailure event when ReceiveMessagesEffect failed `() { // given - val receiveMessagesEffect = ReceiveMessagesEffect(failingRemoteAction(reason), subscribeEventSink) + val receiveMessagesEffect = ReceiveMessagesEffect(failingRemoteAction(reason), subscribeEventSink, logConfig) // when receiveMessagesEffect.runEffect() @@ -65,7 +67,7 @@ class ReceiveMessagesEffectTest { fun `should cancel remoteAction when cancel effect`() { // given val remoteAction: RemoteAction = spyk() - val receiveMessagesEffect = ReceiveMessagesEffect(remoteAction, subscribeEventSink) + val receiveMessagesEffect = ReceiveMessagesEffect(remoteAction, subscribeEventSink, logConfig) // when receiveMessagesEffect.cancel() diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/subscribe/eventengine/effect/SubscribeEffectFactoryTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/subscribe/eventengine/effect/SubscribeEffectFactoryTest.kt index 29739f12f2..30ea64f59f 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/subscribe/eventengine/effect/SubscribeEffectFactoryTest.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/subscribe/eventengine/effect/SubscribeEffectFactoryTest.kt @@ -2,6 +2,7 @@ package com.pubnub.internal.subscribe.eventengine.effect import com.pubnub.api.endpoints.remoteaction.RemoteAction import com.pubnub.api.enums.PNStatusCategory +import com.pubnub.api.logging.LogConfig import com.pubnub.api.models.consumer.PNStatus import com.pubnub.internal.eventengine.ManagedEffect import com.pubnub.internal.eventengine.Sink @@ -31,6 +32,7 @@ class SubscribeEffectFactoryTest { private val handshakeRemoteAction: RemoteAction = mockk() private val receiveMessagesRemoteAction: RemoteAction = mockk() private val statusConsumer = mockk() + private val logConfig = mockk() private val presenceData = PresenceData() @BeforeEach @@ -45,6 +47,7 @@ class SubscribeEffectFactoryTest { statusConsumer, presenceData, true, + logConfig, ) } @@ -141,6 +144,7 @@ class SubscribeEffectFactoryTest { statusConsumer, presenceData, false, + logConfig, ) presenceData.channelStates[channels.first()] = mapOf("aaa" to "bbb") val effectInvocation = SubscribeEffectInvocation.Handshake(channels, channelGroups) diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/v2/subscription/SubscriptionSetImplTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/v2/subscription/SubscriptionSetImplTest.kt index 6b54812a6b..f83c88abcb 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/v2/subscription/SubscriptionSetImplTest.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/v2/subscription/SubscriptionSetImplTest.kt @@ -1,5 +1,6 @@ package com.pubnub.internal.v2.subscription +import com.pubnub.api.logging.LogConfig import com.pubnub.api.v2.subscriptions.EmptyOptions import com.pubnub.api.v2.subscriptions.SubscriptionOptions import com.pubnub.internal.PubNubImpl @@ -23,6 +24,8 @@ class SubscriptionSetImplTest { @BeforeEach fun setUp() { + val testLogConfig = LogConfig("test-instance-id", "test-user-id") + every { pubNubImpl.logConfig } returns testLogConfig val listenerManager = ListenerManager(pubNubImpl) every { pubNubImpl.listenerManager } returns listenerManager diff --git a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/workers/SubscribeMessageProcessorTest.kt b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/workers/SubscribeMessageProcessorTest.kt index 8d777c7b41..8bc3e51872 100644 --- a/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/workers/SubscribeMessageProcessorTest.kt +++ b/pubnub-kotlin/pubnub-kotlin-impl/src/test/kotlin/com/pubnub/internal/workers/SubscribeMessageProcessorTest.kt @@ -10,6 +10,7 @@ import com.pubnub.api.PubNubError import com.pubnub.api.PubNubException import com.pubnub.api.UserId import com.pubnub.api.crypto.CryptoModule +import com.pubnub.api.logging.LogConfig import com.pubnub.api.models.consumer.pubsub.PNMessageResult import com.pubnub.api.models.consumer.pubsub.files.PNFileEventResult import com.pubnub.api.v2.PNConfiguration @@ -204,6 +205,7 @@ class SubscribeMessageProcessorTest( SubscribeMessageProcessor( pubnub = PubNubImpl(configuration), duplicationManager = DuplicationManager(configuration), + logConfig = LogConfig("testPnInstanceId", "testUserId") ) private fun message(messageJson: JsonElement): String {