Skip to content

Commit

Permalink
Merge pull request #2 from logzio/add-tests
Browse files Browse the repository at this point in the history
Add tests & comments
  • Loading branch information
ralongit authored Sep 24, 2023
2 parents c68f969 + 1509f85 commit 86464e2
Show file tree
Hide file tree
Showing 21 changed files with 2,001 additions and 821 deletions.
1 change: 0 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,4 @@ RUN go build -o main .

FROM alpine:3.14
COPY --from=build /app/main /app/main

CMD ["/app/main"]
35 changes: 26 additions & 9 deletions common/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,28 @@ package common

import (
"fmt"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/dynamic" // Importing the dynamic client package
"k8s.io/client-go/kubernetes" // Importing the kubernetes client package
"k8s.io/client-go/rest" // Importing the rest client package
"k8s.io/client-go/tools/clientcmd" // Importing the clientcmd package for building config from kubeconfig
"log"
"os"
"os" // Importing the os package for reading environment variables
)

var K8sClient *kubernetes.Clientset
var DynamicClient *dynamic.DynamicClient
var K8sClient *kubernetes.Clientset // Global variable for the Kubernetes client
var DynamicClient *dynamic.DynamicClient // Global variable for the dynamic client

func CreateClusterClient() {
// Create a Kubernetes client.
// This function creates a Kubernetes client using in-cluster configuration

// Getting the in-cluster configuration
config, err := rest.InClusterConfig()
if err != nil {
fmt.Println(err)
return
}

// Creating the Kubernetes client using the in-cluster configuration
K8sClient, err = kubernetes.NewForConfig(config)
if err != nil {
fmt.Println(err)
Expand All @@ -28,21 +32,34 @@ func CreateClusterClient() {
}

func ConfigureClusterDynamicClient() (clusterClient *dynamic.DynamicClient) {
//
// This function configures a dynamic client for the Kubernetes cluster
// by either using the KUBECONFIG environment variable or falling back to in-cluster configuration

var err error
var clusterConfig *rest.Config

// Reading the KUBECONFIG environment variable
kubeConfig := os.Getenv("KUBECONFIG")
if kubeConfig != "" {
// If KUBECONFIG is set, build the configuration from KUBECONFIG
clusterConfig, err = clientcmd.BuildConfigFromFlags("", kubeConfig)
} else {
// If KUBECONFIG is not set, get the in-cluster configuration
clusterConfig, err = rest.InClusterConfig()
}

// If there is an error in getting the configuration, log the error and exit
if err != nil {
log.Fatalln(err)
}

// Creating the dynamic client using the cluster configuration
clusterClient, err = dynamic.NewForConfig(clusterConfig)

// If there is an error in creating the dynamic client, log the error and exit
if err != nil {
log.Fatalln(err)
}

return clusterClient
}
44 changes: 44 additions & 0 deletions common/client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package common

import (
"k8s.io/apimachinery/pkg/runtime"
fakeDynamic "k8s.io/client-go/dynamic/fake"
"k8s.io/client-go/kubernetes/fake"
"testing"
)

func CreateFakeClient() (mockClient *fake.Clientset) {

mockClient = fake.NewSimpleClientset()

return mockClient
}
func CreateDynamicFakeClient() (mockDynamicClient *fakeDynamic.FakeDynamicClient) {
scheme := runtime.NewScheme()

mockDynamicClient = fakeDynamic.NewSimpleDynamicClient(scheme)

return mockDynamicClient
}

// TestFakeClient demonstrates how to use a fake client with SharedInformerFactory in tests.
func TestFakeDynamicClient(t *testing.T) {
// Create the fake client.
fakeDynamicClient := CreateDynamicFakeClient()
if fakeDynamicClient == nil {
t.Error("Failed to create fake dynamic client")
} else {
t.Log("Created fake dynamic client")
}

}
func TestFakeClusterClient(t *testing.T) {
// Create the fake client.
fakeK8sClient := CreateFakeClient()

if fakeK8sClient == nil {
t.Error("Failed to create fake client")
} else {
t.Log("Created fake client")
}
}
90 changes: 66 additions & 24 deletions common/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,28 @@ package common
import (
"encoding/json"
"fmt"
"github.com/logzio/logzio-go"
"github.com/logzio/logzio-go" // Importing logz.io library for logging
"log"
"os"
"sync"
"time"
)

var LogzioLogger *logzio.LogzioSender
var LogzioLogger *logzio.LogzioSender // Global variable for logz.io logger
var wg sync.WaitGroup // Global variable for wait group

func ConfigureLogzioLogger() (LogzioLogger *logzio.LogzioSender) {
// Creates a resources using Logz.io output configuration: https://app.logz.io/#/dashboard/send-your-data/log-sources/go
func ConfigureLogzioLogger() {
// Function to configure logz.io logger
var err error
LogzioToken := os.Getenv("LOGZIO_TOKEN") // Log shipping token for Logz.io

// Reading logz.io token from environment variables
LogzioToken := os.Getenv("LOGZIO_TOKEN")
if LogzioToken != "" {
LogzioListener := os.Getenv("LOGZIO_LISTENER")
if LogzioListener == "" {
LogzioListener = "https://listener.logz.io:8071" // Defaults to us-east-1 region
}
// Creating a new logz.io logger with specified configuration
LogzioLogger, err = logzio.New(
LogzioToken,
logzio.SetDebug(os.Stderr),
Expand All @@ -29,58 +34,95 @@ func ConfigureLogzioLogger() (LogzioLogger *logzio.LogzioSender) {
logzio.SetDrainDiskThreshold(99),
)
if err != nil {
// If there is an error in creating the logger, log the error and exit
log.Fatalf("\n[FATAL] Failed to configure the Logz.io resources.\nERROR: %v\n", err)
}
} else {
log.Fatalf("\n[FATAL] Invalid token configured for LOGZIO_TOKEN environemt variable.\n")
// If LOGZIO_TOKEN is not set, log error and exit
log.Fatalf("\n[FATAL] Invalid token configured for LOGZIO_TOKEN environment variable.\n")
}
return LogzioLogger
}
func shipLogMessage(message string) {
func shipLogEvent(eventLog string) {
// Function to ship log event to logz.io

log.Printf("\n[LOG]: %s\n", message)
err := LogzioLogger.Send([]byte(message))
// Logging the event
log.Printf("\n[LOG]: %s\n", eventLog)
err := LogzioLogger.Send([]byte(eventLog)) // Sending the log event to logz.io
if err != nil {
log.Printf("\nFailed to send log:\n%v to Logz.io.\nRelated error:\n%v.", message, err)
// If there is an error in sending the log, log the error
log.Printf("\nFailed to send log:\n%v to Logz.io.\nRelated error:\n%v.", eventLog, err)
return
}

LogzioLogger.Drain()
LogzioLogger.Drain() // Draining the logger
defer wg.Done() // Signaling that this function is done
}
func SendLog(msg string, extraFields ...interface{}) {
func ParseEventLog(msg string, extraFields ...interface{}) (eventLog string) {
// This function parses an event log message and any extra fields,
// converting them into a JSON string.

var err error
var parsedEventLog []byte
var logMap map[string]interface{}

// Reading environment variables
environmentID := os.Getenv("ENV_ID")
logType := os.Getenv("LOG_TYPE")

if logType == "" {
logType = "logzio-informer-events"
logType = "logzio-k8s-events" // Default log type
}

// Creating a new log event with the provided message, type and environment ID
logEvent := LogEvent{Message: msg, Type: logType, EnvironmentID: environmentID}

if len(extraFields) > 0 {
// If there are extra fields, convert them to a JSON string and unmarshal into logEvent
extra := fmt.Sprintf("%s", extraFields...)

log.Printf("\n[DEBUG] Attemping to parse log extra data(%T): %s\tlog(%T):\n%v to Logz.io.\n", extra, extra, logEvent, logEvent)

if err := json.Unmarshal([]byte(extra), &logEvent); err != nil && extra != "" {
log.Printf("\n[ERROR] Failed to parse log extra data(%T): %s\tlog(%T):\n%v to Logz.io.\nRelated error:\n%v", extra, logEvent, extra, logEvent, err)
if err = json.Unmarshal([]byte(extra), &logEvent); err != nil && extra != "" && extra != "[]" {
// If there is an error in parsing the extra fields, log the error
log.Printf("\n[ERROR] Failed to parse log extra data(%T): %s\tlog(%T):\n%v to Logz.io.\nRelated error:\n%v", extra, extra, logEvent, logEvent, err)

}
}

// Marshal the log event into a byte slice and unmarshal into logMap
logByte, _ := json.Marshal(&logEvent)
json.Unmarshal(logByte, &logMap)

// Parse the log map to fit logz.io limits
parsedLogMap := parseLogzioLimits(logMap)

// Marshal the parsed log map into a byte slice
parsedEventLog, err = json.Marshal(parsedLogMap)
if err != nil {
// If there is an error in marshaling, log the error
log.Printf("\n[ERROR] Failed to parse event log:\n%v\nERROR:\n%v", logEvent, err)
}

message := fmt.Sprintf("%s", string(parsedEventLog))
if message == "" {
log.Printf("\n[DEBUG]: Empty message, not sending to Logz.io.\n")
} else {
go shipLogMessage(message)
}
// Convert the parsed event log byte slice to a string
//eventLog = fmt.Sprintf("%s", string(parsedEventLog))

return string(parsedEventLog)
}

func SendLog(msg string, extraFields ...interface{}) {
// This function sends a log message and any extra fields to logz.io.

if LogzioLogger != nil {
// Parse the log message and extra fields into a JSON string
eventLog := ParseEventLog(msg, extraFields)

if eventLog == "" {
// If the parsed event log is empty, drop the log
} else {
// Ship the parsed event log to logz.io in a separate goroutine
go shipLogEvent(eventLog)

// Increment the wait group counter and wait for all goroutines to finish
wg.Add(1)
wg.Wait()
}
}
}
76 changes: 76 additions & 0 deletions common/logger_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package common

import (
"github.com/logzio/logzio-go"
"main.go/mockLogzioListener"
"testing"

"os"
"time"
)

func TestStartMockLogzioListener(t *testing.T) {
mockLogzioListener.StartMockLogzioListener()
mockListener := mockLogzioListener.MockListener
if mockListener != nil {
mockListenerURL := mockLogzioListener.GetMockListenerURL()
logsCount := mockListener.NumberOfLogs()
if mockListenerURL != "" {
err := os.Setenv("LOGZIO_TOKEN", "test-shipping-token")
if err != nil {
return
}
err = os.Setenv("LOGZIO_LISTENER", mockListenerURL)
if err != nil {
return
}

if logsCount > 0 {
t.Log("Successfully sent logs.")
}
}
} else {
t.Error("Failed to start mock listener")
}

}

func TestConfigureLogzioLogger(t *testing.T) {
// Creates a resources using Logz.io output configuration: https://app.logz.io/#/dashboard/send-your-data/log-sources/go
var err error
LogzioToken := os.Getenv("LOGZIO_TOKEN") // Log shipping token for Logz.io
if LogzioToken != "" {
LogzioListener := os.Getenv("LOGZIO_LISTENER")
if LogzioListener == "" {
LogzioListener = "https://listener.logz.io:8071" // Defaults to us-east-1 region
}
LogzioLogger, err = logzio.New(
LogzioToken,
logzio.SetDebug(os.Stderr),
logzio.SetUrl(LogzioListener),
logzio.SetDrainDuration(time.Second*5),
logzio.SetTempDirectory("myQueue"),
logzio.SetDrainDiskThreshold(99),
)
if err != nil {
t.Errorf("\n[FATAL] Failed to configure the Logz.io logger.\nERROR: %v\n", err)
} else {
t.Log("Successfully configured the Logz.io logger.\n")
}
} else {
t.Error("\n[FATAL] Invalid token configured for LOGZIO_TOKEN environment variable.\n")
}

}
func TestSendLog(t *testing.T) {

t.Run("SendLog", func(t *testing.T) {
os.Setenv("ENV_ID", "dev")
os.Setenv("LOG_TYPE", "logzio-k8s-events-test")
logsListInstance := mockLogzioListener.GetLogsListInstance()
allLogs := logsListInstance.List
for _, testLog := range allLogs {
SendLog("Test log", testLog)
}
})
}
Loading

0 comments on commit 86464e2

Please sign in to comment.