Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

58 dockter 1 #59

Merged
merged 3 commits into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
6 changes: 3 additions & 3 deletions .testcoverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ local-prefix: "github.com/org/project"
threshold:
# (optional; default 0)
# The minimum coverage that each file should have
file: 85
file: 90

# (optional; default 0)
# The minimum coverage that each package should have
package: 85
package: 90

# (optional; default 0)
# The minimum total coverage project should have
total: 85
total: 90
# Holds regexp rules which will override thresholds for matched files or packages
# using their paths.
#
Expand Down
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

-

## [1.5.0] - 2024-06-04

### Added in 1.5.0

- Suport for `OptionMessageFields`

### Changed in 1.5.0

- From `Interface` to `Messenger`
- From `SimpleMessenger` to `BasicMessenger`

## [1.4.2] - 2024-05-31

### Changed in 1.4.2
Expand Down
8 changes: 6 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,18 @@ func main() {

// Example from README.md

aMessenger, _ := messenger.New()
optionMessageFields := &messenger.OptionMessageFields{
Value: []string{"id", "details"},
}

aMessenger, _ := messenger.New(optionMessageFields)
fmt.Printf("%s\n\n", aMessenger.NewJSON(0001, "Bob", "Mary"))
fmt.Println(aMessenger.NewSlog(1001, "Bob", "Mary"))
fmt.Println()

// Create a bare message generator.

messenger1, err := messenger.New()
messenger1, err := messenger.New(optionMessageFields)
testError(err, "Error: %s\n")

// Print some messages.
Expand Down
21 changes: 16 additions & 5 deletions messenger/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import (
// Types - interface
// ----------------------------------------------------------------------------

// The Interface interface has methods for creating different
// The Messenger interface has methods for creating different
// representations of a message.
type Interface interface {
type Messenger interface {
NewJSON(messageNumber int, details ...interface{}) string
NewSlog(messageNumber int, details ...interface{}) (string, []interface{})
NewSlogLevel(messageNumber int, details ...interface{}) (string, slog.Level, []interface{})
Expand Down Expand Up @@ -106,6 +106,11 @@ type OptionIDStatuses struct {
Value map[int]string // Message number to status map
}

// List of fields included in final message.
type OptionMessageFields struct {
Value []string // One or more of AllMessageFields values.
}

// Format of the unique id.
type OptionMessageIDTemplate struct {
Value string // Format string.
Expand Down Expand Up @@ -199,6 +204,8 @@ var (
ErrEmptyStatuses = errors.New("statuses must be a map[int]string")
)

var AllMessageFields = []string{"details", "duration", "errors", "id", "level", "location", "status", "text", "time"}

// ----------------------------------------------------------------------------
// Public functions
// ----------------------------------------------------------------------------
Expand All @@ -207,9 +214,9 @@ var (
The New function creates a new instance of MessengerInterface.
Adding options can be used to modify subcomponents.
*/
func New(options ...interface{}) (Interface, error) {
func New(options ...interface{}) (Messenger, error) {
var err error
var result Interface
var result Messenger

// Default values.

Expand All @@ -219,6 +226,7 @@ func New(options ...interface{}) (Interface, error) {
idStatuses = map[int]string{}
componentIdentifier = 9999
messageIDTemplate = fmt.Sprintf("SZSDK%04d", componentIdentifier) + "%04d"
messageFields []string
)

// Process options.
Expand All @@ -227,6 +235,8 @@ func New(options ...interface{}) (Interface, error) {
switch typedValue := value.(type) {
case *OptionCallerSkip:
callerSkip = typedValue.Value
case *OptionMessageFields:
messageFields = typedValue.Value
case *OptionIDMessages:
idMessages = typedValue.Value
case *OptionIDStatuses:
Expand Down Expand Up @@ -255,10 +265,11 @@ func New(options ...interface{}) (Interface, error) {

// Create MessengerInterface.

result = &SimpleMessenger{
result = &BasicMessenger{
callerSkip: callerSkip,
idMessages: idMessages,
idStatuses: idStatuses,
messageFields: messageFields,
messageIDTemplate: messageIDTemplate,
}
return result, err
Expand Down
111 changes: 82 additions & 29 deletions messenger/messenger.go → messenger/messenger_basic.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import (
"bytes"
"encoding/json"
"fmt"
"os"
"path/filepath"
"reflect"
"regexp"
"runtime"
"slices"
"sort"
"strings"
"time"
Expand All @@ -19,12 +21,13 @@ import (
// Types
// ----------------------------------------------------------------------------

// SimpleMessenger is an type-struct for an implementation of the MessengerInterface.
type SimpleMessenger struct {
// BasicMessenger is an type-struct for an implementation of the MessengerInterface.
type BasicMessenger struct {
callerSkip int // Levels of code nexting to skip when calculation location
idMessages map[int]string // Map message numbers to text format strings
idStatuses map[int]string
messageFields []string
messageIDTemplate string // A string template for fmt.Sprinf()
callerSkip int // Levels of code nexting to skip when calculation location
sortedIDLevelRanges []int // The keys of IdLevelRanges in sorted order.
}

Expand Down Expand Up @@ -160,7 +163,7 @@ func messageDetails(details ...interface{}) []Detail {

// Create a slice of ["key1", value1, "key2", value2, ...] which has oscillating
// key and values in the slice.
func (messenger *SimpleMessenger) getKeyValuePairs(appMessageFormat *MessageFormat, keys []string) []interface{} {
func (messenger *BasicMessenger) getKeyValuePairs(appMessageFormat *MessageFormat, keys []string) []interface{} {
var result []interface{}
keyValueMap := map[string]interface{}{
"time": appMessageFormat.Time,
Expand Down Expand Up @@ -199,7 +202,7 @@ func (messenger *SimpleMessenger) getKeyValuePairs(appMessageFormat *MessageForm
}

// Given a message number, figure out the Level (TRACE, DEBUG, ..., FATAL, PANIC)
func (messenger *SimpleMessenger) getLevel(messageNumber int) string {
func (messenger *BasicMessenger) getLevel(messageNumber int) string {
sortedMessageLevelKeys := messenger.getSortedIDLevelRanges(IDLevelRangesAsString)
for _, messageLevelKey := range sortedMessageLevelKeys {
if messageNumber >= messageLevelKey {
Expand All @@ -210,7 +213,7 @@ func (messenger *SimpleMessenger) getLevel(messageNumber int) string {
}

// Since a map[int]any is not guaranteed to be in order, return an ordered slice of int.
func (messenger *SimpleMessenger) getSortedIDLevelRanges(idLevelRanges map[int]string) []int {
func (messenger *BasicMessenger) getSortedIDLevelRanges(idLevelRanges map[int]string) []int {
if messenger.sortedIDLevelRanges == nil {
messenger.sortedIDLevelRanges = make([]int, 0, len(idLevelRanges))
for key := range idLevelRanges {
Expand All @@ -221,17 +224,37 @@ func (messenger *SimpleMessenger) getSortedIDLevelRanges(idLevelRanges map[int]s
return messenger.sortedIDLevelRanges
}

func (messenger *BasicMessenger) populateMessageFields() {
senzingMessageFields := strings.TrimSpace(strings.ToLower(os.Getenv("SENZING_MESSAGE_FIELDS")))
switch {
case len(senzingMessageFields) == 0:
messenger.messageFields = []string{"id", "text"}
case senzingMessageFields == "all":
messenger.messageFields = AllMessageFields
default:
messenger.messageFields = []string{}
messageSplits := strings.Split(senzingMessageFields, ",")
for _, value := range messageSplits {
valueTrimmed := strings.TrimSpace(value)
if slices.Contains(AllMessageFields, valueTrimmed) {
messenger.messageFields = append(messenger.messageFields, valueTrimmed)
}
}
}
}

// Create a populated MessageFormat.
func (messenger *SimpleMessenger) populateStructure(messageNumber int, details ...interface{}) *MessageFormat {
func (messenger *BasicMessenger) populateStructure(messageNumber int, details ...interface{}) *MessageFormat {

var (
callerSkip int
duration int64
errorList []interface{}
level string
location string
status string
text string
callerSkip int
duration int64
errorList []interface{}
level string
location string
messageFields []string
status string
text string
)

// Calculate fields.
Expand Down Expand Up @@ -283,6 +306,8 @@ func (messenger *SimpleMessenger) populateStructure(messageNumber int, details .
timeNow = typedValue.Value.Format(time.RFC3339Nano)
case *OptionCallerSkip:
callerSkip = typedValue.Value
case *OptionMessageFields:
messageFields = typedValue.Value
case error:
errorList = append(errorList, cleanErrorString(typedValue))
filteredDetails = append(filteredDetails, typedValue)
Expand Down Expand Up @@ -315,23 +340,51 @@ func (messenger *SimpleMessenger) populateStructure(messageNumber int, details .
}
}

// Determine fields to print.

if messageFields == nil {
if messenger.messageFields == nil {
messenger.populateMessageFields()
}
messageFields = messenger.messageFields
}

// Compose result.

result := &MessageFormat{
Time: timeNow,
Level: level,
ID: id,
Text: text,
Status: status,
Duration: duration,
Location: location,
result := &MessageFormat{}

if slices.Contains(messageFields, "details") {
if len(filteredDetails) > 0 {
result.Details = messageDetails(filteredDetails...)
}
}
if slices.Contains(messageFields, "duration") {
result.Duration = duration
}
if slices.Contains(messageFields, "errors") {
if len(errorList) > 0 {
result.Errors = errorList
}
}
if len(errorList) > 0 {
result.Errors = errorList
if slices.Contains(messageFields, "id") {
result.ID = id
}
if len(filteredDetails) > 0 {
result.Details = messageDetails(filteredDetails...)
if slices.Contains(messageFields, "level") {
result.Level = level
}
if slices.Contains(messageFields, "location") {
result.Location = location
}
if slices.Contains(messageFields, "status") {
result.Status = status
}
if slices.Contains(messageFields, "text") {
result.Text = text
}
if slices.Contains(messageFields, "time") {
result.Time = timeNow
}

return result
}

Expand All @@ -349,7 +402,7 @@ Input
Output
- A JSON string representing the details formatted by the template identified by the messageNumber.
*/
func (messenger *SimpleMessenger) NewJSON(messageNumber int, details ...interface{}) string {
func (messenger *BasicMessenger) NewJSON(messageNumber int, details ...interface{}) string {
messageFormat := messenger.populateStructure(messageNumber, details...)

// Construct return value.
Expand Down Expand Up @@ -383,7 +436,7 @@ Output
- A text message
- A slice of oscillating key-value pairs.
*/
func (messenger *SimpleMessenger) NewSlog(messageNumber int, details ...interface{}) (string, []interface{}) {
func (messenger *BasicMessenger) NewSlog(messageNumber int, details ...interface{}) (string, []interface{}) {
message, _, keyValuePairs := messenger.NewSlogLevel(messageNumber, details...)
return message, keyValuePairs
}
Expand All @@ -400,7 +453,7 @@ Output
- A message level
- A slice of oscillating key-value pairs.
*/
func (messenger *SimpleMessenger) NewSlogLevel(messageNumber int, details ...interface{}) (string, slog.Level, []interface{}) {
func (messenger *BasicMessenger) NewSlogLevel(messageNumber int, details ...interface{}) (string, slog.Level, []interface{}) {
messageFormat := messenger.populateStructure(messageNumber, details...)

// Create a text message.
Expand Down
18 changes: 9 additions & 9 deletions messenger/messenger_examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,32 @@ import (
// Examples for godoc documentation
// ----------------------------------------------------------------------------

func ExampleSimpleMessenger_NewJSON() {
func ExampleBasicMessenger_NewJSON() {
// For more information, visit https://github.com/senzing-garage/go-messaging/blob/main/messenger/messenger_examples_test.go
example, err := New()
if err != nil {
fmt.Println(err)
}
fmt.Print(example.NewJSON(2001, "Bob", "Jane", getTimestamp(), getOptionCallerSkip()))
//Output: {"time":"2000-01-01T00:00:00Z","level":"INFO","id":"SZSDK99992001","location":"In ExampleSimpleMessenger_NewJSON() at messenger_examples_test.go:17","details":[{"position":1,"type":"string","value":"Bob"},{"position":2,"type":"string","value":"Jane"}]}
fmt.Print(example.NewJSON(2001, "Bob", "Jane", getOptionMessageFields()))
//Output: {"level":"INFO","id":"SZSDK99992001","details":[{"position":1,"type":"string","value":"Bob"},{"position":2,"type":"string","value":"Jane"}]}
}

func ExampleSimpleMessenger_NewSlog() {
func ExampleBasicMessenger_NewSlog() {
// For more information, visit https://github.com/senzing-garage/go-messaging/blob/main/messenger/messenger_examples_test.go
example, err := New()
if err != nil {
fmt.Println(err)
}
fmt.Print(example.NewSlog(2001, "Bob", "Jane", getTimestamp(), getOptionCallerSkip()))
//Output: [id SZSDK99992001 location In NewSlog() at messenger.go:387 details [{ 1 string Bob <nil>} { 2 string Jane <nil>}]]
fmt.Print(example.NewSlog(2001, "Bob", "Jane", getOptionMessageFields()))
//Output: [id SZSDK99992001 details [{ 1 string Bob <nil>} { 2 string Jane <nil>}]]
}

func ExampleSimpleMessenger_NewSlogLevel() {
func ExampleBasicMessenger_NewSlogLevel() {
// For more information, visit https://github.com/senzing-garage/go-messaging/blob/main/messenger/messenger_examples_test.go
example, err := New()
if err != nil {
fmt.Println(err)
}
fmt.Print(example.NewSlogLevel(2001, "Bob", "Jane", getTimestamp(), getOptionCallerSkip()))
//Output: INFO [id SZSDK99992001 location In ExampleSimpleMessenger_NewSlogLevel() at messenger_examples_test.go:37 details [{ 1 string Bob <nil>} { 2 string Jane <nil>}]]
fmt.Print(example.NewSlogLevel(2001, "Bob", "Jane", getOptionMessageFields()))
//Output: INFO [id SZSDK99992001 details [{ 1 string Bob <nil>} { 2 string Jane <nil>}]]
}
Loading