Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/streaming-jakarta.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ jobs:
with:
go-version: '${{ matrix.go-version }}'

- name: Verify Examples
- name: Verify
shell: bash
run: |
go get google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.3.0
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/streaming.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ jobs:
with:
go-version: '${{ matrix.go-version }}'

- name: Verify Examples
- name: Verify
shell: bash
run: |
go get google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.3.0
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
# ----------------------------------------------------------------------------------------------------------------------

# This is the version of the coherence-go-client
VERSION ?=2.1.0
VERSION ?=2.1.1
CURRDIR := $(shell pwd)
USER_ID := $(shell echo "`id -u`:`id -g`")

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ For local development, we recommend using the Coherence CE Docker image; it cont
everything necessary for the client to operate correctly.

```bash
docker run -d -p 1408:1408 -p 30000:30000 ghcr.io/oracle/coherence-ce:24.09.3
docker run -d -p 1408:1408 -p 30000:30000 ghcr.io/oracle/coherence-ce:25.03.1
```

## Installation
Expand Down
11 changes: 7 additions & 4 deletions coherence/common.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024 Oracle and/or its affiliates.
* Copyright (c) 2022, 2025 Oracle and/or its affiliates.
* Licensed under the Universal Permissive License v 1.0 as shown at
* https://oss.oracle.com/licenses/upl.
*/
Expand Down Expand Up @@ -35,13 +35,13 @@ const (
envDisconnectTimeout = "COHERENCE_SESSION_DISCONNECT_TIMEOUT"
envReadyTimeout = "COHERENCE_READY_TIMEOUT"

// envSessionDebug enables session debug messages to be displayed.
// envSessionDebug enables session debug messages to be displayed. Deprecated, use COHERENCE_LOG_LEVEL=DEBUG instead.
envSessionDebug = "COHERENCE_SESSION_DEBUG"

// envMessageDebug enables message debug messages to be displayed.
// envMessageDebug enables message debug messages to be displayed. Deprecated, use COHERENCE_LOG_LEVEL=ALL instead.
envMessageDebug = "COHERENCE_MESSAGE_DEBUG"

// envResolverDebug enables resolver debug messages to be displayed.
// envResolverDebug enables resolver debug messages to be displayed. Deprecated, use COHERENCE_LOG_LEVEL=DEBUG instead.
envResolverDebug = "COHERENCE_RESOLVER_DEBUG"

// envResolverDebug sets the number of retries when the resolver fails.
Expand All @@ -50,6 +50,9 @@ const (
// envResolverDebug enables randomization of addresses returned by resolver
envResolverRandomize = "COHERENCE_RESOLVER_RANDOMIZE"

// the Coherence log level: 1 -> 5 (ERROR -> ALL)
envLogLevel = "COHERENCE_LOG_LEVEL"

// Integer.MAX_VALUE on Java
integerMaxValue = 2147483647

Expand Down
21 changes: 21 additions & 0 deletions coherence/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,27 @@ You also have the ability to control maximum amount of time, in milliseconds, a
without successfully reconnecting. For this you use the option [coherence.WithDisconnectTimeout] or the environment
variable COHERENCE_SESSION_DISCONNECT_TIMEOUT.

# Setting Log Levels

The Coherence Go client supports setting the following log levels to change verbosity of messages output.
The default level is 'INFO' and this can be changed by setting the environment variable COHERENCE_LOG_LEVEL to one of the following values:

- ERROR

- WARNING

- INFO

- DEBUG

- ALL

All messages at and above the level are displayed. For example setting to WARNING will only show ERROR and WARNING messages.
Where as setting DEBUG, will show ERROR, WARNING, INFO and DEBUG messages.

Note: Setting to ALL should only be used to diagnose issues as directed by Oracle Support. This level will
output a large volume of messages.

# Obtaining a NamedMap or NamedCache

Once a session has been created, the [GetNamedMap](session, name, ...options) or [GetNamedCache](session, name, ...options)
Expand Down
67 changes: 67 additions & 0 deletions coherence/log_level_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright (c) 2025 Oracle and/or its affiliates.
* Licensed under the Universal Permissive License v 1.0 as shown at
* https://oss.oracle.com/licenses/upl.
*/

package coherence

import (
"bytes"
"github.com/onsi/gomega"
"log"
"testing"
)

func TestErrorLogLevel(t *testing.T) {
runLogLevelTest(t, ERROR, ERROR, true)
runLogLevelTest(t, WARNING, ERROR, false)
runLogLevelTest(t, INFO, ERROR, false)
runLogLevelTest(t, DEBUG, ERROR, false)
runLogLevelTest(t, ALL, ERROR, false)

runLogLevelTest(t, ERROR, WARNING, true)
runLogLevelTest(t, WARNING, WARNING, true)
runLogLevelTest(t, INFO, WARNING, false)
runLogLevelTest(t, DEBUG, WARNING, false)
runLogLevelTest(t, ALL, WARNING, false)

runLogLevelTest(t, ERROR, INFO, true)
runLogLevelTest(t, WARNING, INFO, true)
runLogLevelTest(t, INFO, INFO, true)
runLogLevelTest(t, DEBUG, INFO, false)
runLogLevelTest(t, ALL, INFO, false)

runLogLevelTest(t, ERROR, DEBUG, true)
runLogLevelTest(t, WARNING, DEBUG, true)
runLogLevelTest(t, INFO, DEBUG, true)
runLogLevelTest(t, DEBUG, DEBUG, true)
runLogLevelTest(t, ALL, DEBUG, false)

runLogLevelTest(t, ERROR, ALL, true)
runLogLevelTest(t, WARNING, ALL, true)
runLogLevelTest(t, INFO, ALL, true)
runLogLevelTest(t, DEBUG, ALL, true)
runLogLevelTest(t, ALL, ALL, true)
}

func runLogLevelTest(t *testing.T, messageLevel, testLogLevel logLevel, expectOutput bool) {
g := gomega.NewWithT(t)
const message = "MESSAGE"

var buf bytes.Buffer

origOutput := log.Writer()
log.SetOutput(&buf)
defer log.SetOutput(origOutput)
setLogLevel(testLogLevel.String())

logMessage(messageLevel, message)
output := buf.String()

if expectOutput {
g.Expect(output).To(gomega.ContainSubstring(message))
} else {
g.Expect(output).To(gomega.Not(gomega.ContainSubstring(message)))
}
}
9 changes: 4 additions & 5 deletions coherence/named_map_client.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024 Oracle and/or its affiliates.
* Copyright (c) 2022, 2025 Oracle and/or its affiliates.
* Licensed under the Universal Permissive License v 1.0 as shown at
* https://oss.oracle.com/licenses/upl.
*/
Expand All @@ -14,7 +14,6 @@ import (
"github.com/oracle/coherence-go-client/v2/coherence/extractors"
"github.com/oracle/coherence-go-client/v2/coherence/filters"
"github.com/oracle/coherence-go-client/v2/coherence/processors"
"log"
"sync"
"time"
)
Expand Down Expand Up @@ -456,7 +455,7 @@ func (nm *NamedMapClient[K, V]) Release() {
if nm.baseClient.nearCacheListener != nil {
err := nm.RemoveListener(context.Background(), nm.baseClient.nearCacheListener.listener)
if err != nil {
log.Printf("unable to remove listener to near cache: %v", err)
logMessage(WARNING, "unable to remove listener to near cache: %v", err)
}
}

Expand Down Expand Up @@ -995,7 +994,7 @@ func newNamedMapReconnectListener[K comparable, V any](nm NamedMapClient[K, V])
// re-register listeners for the NamedMap
namedMap := convertNamedMapClient[K, V](&nm)
if err := reRegisterListeners[K, V](context.Background(), &namedMap, nm.baseClient); err != nil {
log.Println(err)
logMessage(WARNING, "unable to re-register listeners: %v", err)
}
})

Expand Down Expand Up @@ -1057,7 +1056,7 @@ func newNearNamedMapMapLister[K comparable, V any](nc NamedMapClient[K, V], cach
listener.listener.OnAny(func(e MapEvent[K, V]) {
err := processNearCacheEvent(nc.baseClient.nearCache, e)
if err != nil {
log.Println("Error processing near cache MapEvent", e)
logMessage(WARNING, "Error processing near cache MapEvent: %v", e)
}
})

Expand Down
3 changes: 1 addition & 2 deletions coherence/processors/processors.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024 Oracle and/or its affiliates.
* Copyright (c) 2022, 2025 Oracle and/or its affiliates.
* Licensed under the Universal Permissive License v 1.0 as shown at
* https://oss.oracle.com/licenses/upl.
*/
Expand All @@ -15,7 +15,6 @@ import (
const (
processorPrefix = "processor."
extractorPrefix = "extractor."
queuePrefix = "internal.net.queue.processor."

compositeProcessorType = processorPrefix + "CompositeProcessor"
conditionalProcessorType = processorPrefix + "ConditionalProcessor"
Expand Down
7 changes: 5 additions & 2 deletions coherence/resolver.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024 Oracle and/or its affiliates.
* Copyright (c) 2022, 2025 Oracle and/or its affiliates.
* Licensed under the Universal Permissive License v 1.0 as shown at
* https://oss.oracle.com/licenses/upl.
*/
Expand Down Expand Up @@ -219,10 +219,13 @@ func parseNsLookupString(addresses string) ([]string, error) {
}

func checkResolverDebug() {
if getBoolValueFromEnvVarOrDefault(envResolverDebug, false) {
if getBoolValueFromEnvVarOrDefault(envResolverDebug, false) || currentLogLevel >= int(DEBUG) {
// enable session debugging
resolverDebug = func(s string, v ...any) {
logMessage(DEBUG, s, v...)
}
if currentLogLevel <= int(DEBUG) {
currentLogLevel = int(DEBUG)
}
}
}
67 changes: 49 additions & 18 deletions coherence/session.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024 Oracle and/or its affiliates.
* Copyright (c) 2022, 2025 Oracle and/or its affiliates.
* Licensed under the Universal Permissive License v 1.0 as shown at
* https://oss.oracle.com/licenses/upl.
*/
Expand All @@ -20,7 +20,6 @@ import (
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/resolver"
"google.golang.org/grpc/status"
"log"
"os"
"reflect"
"strconv"
Expand Down Expand Up @@ -72,9 +71,8 @@ type Session struct {
connectMutex sync.RWMutex // mutes for connection attempts
firstConnectAttempted bool // indicates if the first connection has been attempted
hasConnected bool // indicates if the session has ever connected
debug func(string, ...any) // a function to output debug messages
debugConnection func(string, ...any) // a function to output debug messages for gRPCV1 connections
messageDebugMode string // either "on" or "full"
debug func(string, ...any) // a function to output DEBUG messages
debugConnection func(string, ...any) // a function to output ALL messages for gRPCV1 connections
requestID int64 // request id for gRPC v1
filterID int64 // filter id for gRPC v1
v1StreamManagerCache *streamManagerV1
Expand Down Expand Up @@ -192,24 +190,26 @@ func NewSession(ctx context.Context, options ...func(session *SessionOptions)) (
// ensure name resolver has been registered
resolver.Register(&nsLookupResolverBuilder{})

if getBoolValueFromEnvVarOrDefault(envSessionDebug, false) {
// set the coherenceLogLevel
setLogLevel(getStringValueFromEnvVarOrDefault(envLogLevel, "3"))

if getBoolValueFromEnvVarOrDefault(envSessionDebug, false) || currentLogLevel >= int(DEBUG) {
// enable session debugging
session.debug = func(format string, v ...any) {
logMessage(DEBUG, format, v...)
}
if currentLogLevel <= int(DEBUG) {
currentLogLevel = int(DEBUG)
}
}

messageDebug := getStringValueFromEnvVarOrDefault(envMessageDebug, "")
if messageDebug != "" {
if messageDebug != "" || currentLogLevel == int(ALL) {
// enable session debugging
session.debugConnection = func(s string, v ...any) {
msg := getLogMessage(DEBUG, s, v...)
if session.messageDebugMode == "on" && len(msg) > 256 {
msg = msg[:256]
}
log.Println(msg)
logMessage(DEBUG, s, v...)
}
session.messageDebugMode = messageDebug
currentLogLevel = int(ALL)
}

// apply any options
Expand Down Expand Up @@ -257,6 +257,37 @@ func NewSession(ctx context.Context, options ...func(session *SessionOptions)) (
return session, session.ensureConnection()
}

// setLogLevel sets the log level from the COHERENCE_LOG_LEVEL environment variable.
func setLogLevel(envLevel string) {
var level int

// try to convert from integer first
if lvl, err := strconv.Atoi(envLevel); err == nil {
if lvl >= 1 && lvl <= 5 {
currentLogLevel = lvl
return
}
}

// fall-through, check for string values
switch envLevel {
case "ERROR":
level = 1
case "WARNING":
level = 2
case "INFO":
level = 3
case "DEBUG":
level = 4
case "ALL":
level = 5
default:
level = 3 // INFO
}

currentLogLevel = level
}

func getTimeoutValue(envVar, defaultValue, description string) (time.Duration, error) {
timeoutString := getStringValueFromEnvVarOrDefault(envVar, defaultValue)
timeout, err := strconv.ParseInt(timeoutString, 10, 64)
Expand Down Expand Up @@ -418,7 +449,7 @@ func (s *Session) Close() {
return newSessionLifecycleEvent(s, Closed)
})
if err != nil {
log.Printf("unable to close session %s %v", s.sessionID, err)
logMessage(WARNING, "unable to close session %s %v", s.sessionID, err)
}
} else {
defer s.mapMutex.Unlock()
Expand Down Expand Up @@ -753,7 +784,7 @@ func (s *SessionOptions) createTLSOption() (grpc.DialOption, error) {
// check if a tls.Config has been set and use this, otherwise continue to check for env and other options
if s.TlSConfig != nil {
if s.TlSConfig.InsecureSkipVerify {
log.Println(insecureWarning)
logMessage(WARNING, insecureWarning)
}
return grpc.WithTransportCredentials(credentials.NewTLS(s.TlSConfig)), nil
}
Expand All @@ -774,7 +805,7 @@ func (s *SessionOptions) createTLSOption() (grpc.DialOption, error) {

ignoreInvalidCerts := ignoreInvalidCertsEnv == "true"
if ignoreInvalidCerts {
log.Println(insecureWarning)
logMessage(WARNING, insecureWarning)
}
s.IgnoreInvalidCerts = ignoreInvalidCerts

Expand All @@ -801,7 +832,7 @@ func (s *SessionOptions) createTLSOption() (grpc.DialOption, error) {
if s.CaCertPath != "" {
cp = x509.NewCertPool()

log.Println("loading CA certificate")
logMessage(DEBUG, "loading CA certificate")
if err = validateFilePath(s.CaCertPath); err != nil {
return nil, err
}
Expand All @@ -817,7 +848,7 @@ func (s *SessionOptions) createTLSOption() (grpc.DialOption, error) {
}

if s.ClientCertPath != "" && s.ClientKeyPath != "" {
log.Println("loading client certificate and key, cert=", s.ClientCertPath, "key=", s.ClientKeyPath)
logMessage(DEBUG, "loading client certificate and key paths, cert=%s, key=%s", s.ClientCertPath, s.ClientKeyPath)
if err = validateFilePath(s.ClientCertPath); err != nil {
return nil, err
}
Expand Down
Loading
Loading