From 7d14ddd90e504524b30dac7a999da28a43bd8ccc Mon Sep 17 00:00:00 2001 From: gab-arrobo Date: Fri, 1 Nov 2024 17:44:06 -0700 Subject: [PATCH] Refactor path for configuration file, option(s) and Docker image (#94) Signed-off-by: Arrobo, Gabriel --- .golangci.yml | 42 ++++++------------ Dockerfile | 13 ++---- api/apiserver/api_handler.go | 62 +++++++++++++++++--------- controller/controller.go | 74 +++++++++++++++---------------- internal/promclient/promclient.go | 19 ++++++-- metricfunc.go | 2 +- 6 files changed, 111 insertions(+), 101 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index b00922e..d1000aa 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,8 +1,6 @@ # SPDX-FileCopyrightText: 2022-present Intel Corporation -# # SPDX-License-Identifier: Apache-2.0 - # This file contains all available configuration options # with their default values. # options for analysis running @@ -27,19 +25,6 @@ run: # default is true. Enables skipping of directories: # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ skip-dirs-use-default: true - # which files to skip: they will be analyzed, but issues from them - # won't be reported. Default value is empty list, but there is - # no need to include all autogenerated files, we confidently recognize - # autogenerated files. If it's not please let us know. - # "/" will be replaced by current OS file path separator to properly work - # on Windows. - skip-files: - - "api_.*\\.go$" - - "model_.*\\.go$" - - "routers.go" - - "client.go" - - "configuration.go" - - "nas.go" # by default isn't set. If set we pass it to "go list -mod={option}". From "go help modules": # If invoked with -mod=readonly, the go command is disallowed from the implicit # automatic updating of go.mod described above. Instead, it fails when any changes @@ -55,7 +40,7 @@ run: # output configuration options output: # colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number" - format: colored-line-number + formats: colored-line-number # print lines of code with issue, default is true print-issued-lines: true # print linter name in the end of issue text, default is true @@ -138,10 +123,14 @@ linters-settings: # minimal confidence for issues, default is 0.8 min-confidence: 0.8 gomnd: - settings: - mnd: - # the list of enabled checks, see https://github.com/tommy-muehle/go-mnd/#checks for description. - checks: argument,case,condition,operation,return,assign + # the list of enabled checks, see https://github.com/tommy-muehle/go-mnd/#checks for description. + checks: + - argument + - case + - condition + - operation + - return + - assign gomodguard: allowed: modules: # List of allowed modules @@ -159,8 +148,6 @@ linters-settings: # version: "< 1.1.0" # Version constraint, see https://github.com/Masterminds/semver#basic-comparisons # reason: "testing if blocked version constraint works." # Reason why the version constraint exists. (Optional) govet: - # report about shadowed variables - check-shadowing: true # settings per analyzer settings: printf: # analyzer name, run `go tool vet help` to see all analyzers @@ -208,8 +195,6 @@ linters-settings: whitespace: multi-if: false # Enforces newlines (or comments) after every multi-line if statement multi-func: false # Enforces newlines (or comments) after every multi-line function signature - gci: - local-prefixes: "bitbucket.org" misspell: #locale: US ignore-words: @@ -230,9 +215,8 @@ linters: - lll - godox #- gomnd - #- goconst + - goconst # - gocognit - # - maligned # - nestif # - gomodguard - nakedret @@ -246,9 +230,9 @@ linters: - dogsled # - bodyclose - asciicheck - #- stylecheck - # - unparam - #- wsl + # - stylecheck + # - unparam + # - wsl #disable-all: false fast: true diff --git a/Dockerfile b/Dockerfile index ac8ab70..d93ad0b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,15 +5,14 @@ FROM golang:1.23.2-bookworm AS builder -LABEL maintainer="Aether SD-Core " - WORKDIR $GOPATH/src/metricfunc COPY . . RUN make all FROM alpine:3.20 AS metricfunc -LABEL description="Aether open source 5G Core Network" \ +LABEL maintainer="Aether SD-Core " \ + description="Aether open source 5G Core Network" \ version="Stage 3" ARG DEBUG_TOOLS @@ -23,11 +22,5 @@ RUN if [ "$DEBUG_TOOLS" = "true" ]; then \ apk update && apk add --no-cache -U vim strace net-tools curl netcat-openbsd bind-tools tcpdump; \ fi -# Set working dir -WORKDIR /metricfunc/bin - # Copy executable -COPY --from=builder /go/src/metricfunc/bin/* . - -#Image default directory -WORKDIR /metricfunc +COPY --from=builder /go/src/metricfunc/bin/* /usr/local/bin/. diff --git a/api/apiserver/api_handler.go b/api/apiserver/api_handler.go index 7330701..b416347 100644 --- a/api/apiserver/api_handler.go +++ b/api/apiserver/api_handler.go @@ -16,36 +16,44 @@ import ( ) func GetSubscriberSummary(c *gin.Context) { - subId := c.Params.ByName("imsi") - sub, _ := metricdata.GetSubscriber(subId) + sub, err := metricdata.GetSubscriber(subId) + if err != nil { + logger.ApiSrvLog.Errorf("get subscriber error: %+v", err) + } + if sub != nil { resBody, err := openapi.Serialize(sub, "application/json") + if err != nil { + logger.ApiSrvLog.Errorf("json marshal error: %+v", err) + } + _, err = c.Writer.Write(resBody) if err != nil { - logger.ApiSrvLog.Errorf("json Marshal error %s", err.Error()) + logger.ApiSrvLog.Errorf("write data error: %+v", err) } - c.Writer.Write(resBody) c.Status(http.StatusOK) return } - logger.ApiSrvLog.Errorf("subscriber data not found, imsi [%s] ", subId) + logger.ApiSrvLog.Errorf("subscriber data not found, imsi [%s]", subId) c.JSON(http.StatusNotFound, gin.H{}) } func GetSubscriberAll(c *gin.Context) { - subs := metricdata.GetSubscriberAll() if len(subs) != 0 { resBody, err := openapi.Serialize(subs, "application/json") + if err != nil { + logger.ApiSrvLog.Errorf("json marshal error %+v", err) + } + _, err = c.Writer.Write(resBody) if err != nil { - logger.ApiSrvLog.Errorf("json Marshal error %s", err.Error()) + logger.ApiSrvLog.Errorf("write data error: %+v", err) } - c.Writer.Write(resBody) c.Status(http.StatusOK) return } @@ -60,16 +68,19 @@ func GetNfStatus(c *gin.Context) { nfs := metricdata.GetNfStatusbyNfType(nfType) if len(nfs) != 0 { resBody, err := openapi.Serialize(nfs, "application/json") + if err != nil { + logger.ApiSrvLog.Errorf("json marshal error: %+v", err) + } + _, err = c.Writer.Write(resBody) if err != nil { - logger.ApiSrvLog.Errorf("json Marshal error %s", err.Error()) + logger.ApiSrvLog.Errorf("write data error: %+v", err) } - c.Writer.Write(resBody) c.Status(http.StatusOK) return } - logger.ApiSrvLog.Errorf("no nfs data not found ") + logger.ApiSrvLog.Errorln("no nfs data not found") c.JSON(http.StatusNotFound, gin.H{}) } @@ -78,21 +89,24 @@ func GetNfStatusAll(c *gin.Context) { if len(nfs) != 0 { resBody, err := openapi.Serialize(nfs, "application/json") + if err != nil { + logger.ApiSrvLog.Errorf("json marshal error %+v", err) + } + _, err = c.Writer.Write(resBody) if err != nil { - logger.ApiSrvLog.Errorf("json Marshal error %s", err.Error()) + logger.ApiSrvLog.Errorf("write data error: %+v", err) } - c.Writer.Write(resBody) + c.Status(http.StatusOK) return } - logger.ApiSrvLog.Errorf("no nfs data not found ") + logger.ApiSrvLog.Errorln("no nfs data not found") c.JSON(http.StatusNotFound, gin.H{}) } // Gives summary stats for any service func GetNfServiceStatsSummary(c *gin.Context) { - } // Gives detail stats of any service @@ -102,13 +116,18 @@ func GetNfServiceStatsDetail(c *gin.Context) { if svcStats, err := metricdata.GetNfServiceStatsDetail(nfType); err == nil { resBody, err := openapi.Serialize(svcStats, "application/json") if err != nil { - logger.ApiSrvLog.Errorf("json Marshal error %s", err.Error()) + logger.ApiSrvLog.Errorf("json marshal error: %+v", err) + } + + _, err = c.Writer.Write(resBody) + if err != nil { + logger.ApiSrvLog.Errorf("write data error: %+v", err) } - c.Writer.Write(resBody) + c.Status(http.StatusOK) return } - logger.ApiSrvLog.Errorf("no nf service statistics data not found ") + logger.ApiSrvLog.Errorln("no nf service statistics data not found") c.JSON(http.StatusNotFound, gin.H{}) } @@ -119,11 +138,14 @@ func GetNfServiceStatsAll(c *gin.Context) { func PushTestIPs(c *gin.Context) { requestBody, err := c.GetRawData() if err != nil { - logger.ApiSrvLog.Errorf("get requestbody error %s", err.Error()) + logger.ApiSrvLog.Errorf("get requestbody error: %+v", err) return } var rogueIPs controller.RogueIPs - json.Unmarshal(requestBody, &rogueIPs) + err = json.Unmarshal(requestBody, &rogueIPs) + if err != nil { + logger.ApiSrvLog.Errorf("json unmarshal error: %+v", err) + } logger.ApiSrvLog.Infoln("Test RogueIPs: ", rogueIPs) controller.RogueChannel <- rogueIPs diff --git a/controller/controller.go b/controller/controller.go index 9d71696..af26052 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -85,17 +85,17 @@ func InitControllerConfig(CConfig *config.Config) error { ControllerConfig.Configuration.UserAppApiServer.PollInterval = 30 } - logger.ControllerLog.Infoln("Ons Api Server Endpoint:") + logger.ControllerLog.Infoln("ons Api Server Endpoint:") addr := ControllerConfig.Configuration.UserAppApiServer.Addr ControllerConfig.Configuration.UserAppApiServer.Addr = strings.TrimSpace(addr) - logger.ControllerLog.Infoln("Address", ControllerConfig.Configuration.UserAppApiServer.Addr) - logger.ControllerLog.Infoln("Port", ControllerConfig.Configuration.UserAppApiServer.Port) - logger.ControllerLog.Infoln("PollInterval", ControllerConfig.Configuration.UserAppApiServer.PollInterval) + logger.ControllerLog.Infoln("address", ControllerConfig.Configuration.UserAppApiServer.Addr) + logger.ControllerLog.Infoln("port", ControllerConfig.Configuration.UserAppApiServer.Port) + logger.ControllerLog.Infoln("pollInterval", ControllerConfig.Configuration.UserAppApiServer.PollInterval) - logger.ControllerLog.Infoln("Roc Endpoint:") + logger.ControllerLog.Infoln("roc Endpoint:") ControllerConfig.Configuration.RocEndPoint.Addr = strings.TrimSpace(ControllerConfig.Configuration.RocEndPoint.Addr) - logger.ControllerLog.Infoln("Address", ControllerConfig.Configuration.RocEndPoint.Addr) - logger.ControllerLog.Infoln("Port", ControllerConfig.Configuration.RocEndPoint.Port) + logger.ControllerLog.Infoln("address", ControllerConfig.Configuration.RocEndPoint.Addr) + logger.ControllerLog.Infoln("port", ControllerConfig.Configuration.RocEndPoint.Port) return nil } @@ -114,7 +114,7 @@ func getNextBackoffInterval(retry, interval uint) uint { func sendHttpReqMsgWithoutRetry(req *http.Request) (*http.Response, error) { rsp, err := client.Do(req) if err != nil { - logger.ControllerLog.Errorf("http req send error [%v]", err.Error()) + logger.ControllerLog.Errorf("http req send error [%+v]", err) return nil, err } @@ -135,7 +135,7 @@ func sendHttpReqMsgWithoutRetry(req *http.Request) (*http.Response, error) { } func sendHttpReqMsg(req *http.Request) (*http.Response, error) { - // Keep sending request to Http server until response is success + // Keep sending request to http server until response is success var retries uint = 0 var body []byte var err error @@ -153,7 +153,7 @@ func sendHttpReqMsg(req *http.Request) (*http.Response, error) { retries += 1 if err != nil { nextInterval := getNextBackoffInterval(retries, 2) - logger.ControllerLog.Warnf("http req send error [%v], retrying after %v sec...", err.Error(), nextInterval) + logger.ControllerLog.Warnf("http req send error [%+v], retrying after %v sec...", err, nextInterval) time.Sleep(time.Second * time.Duration(nextInterval)) continue } @@ -185,28 +185,28 @@ func sendHttpReqMsg(req *http.Request) (*http.Response, error) { func validateIPs(ips RogueIPs) (validIps RogueIPs) { for _, ip := range ips.IpAddresses { if net.ParseIP(ip) == nil { - logger.ControllerLog.Errorf("UserAppApp response received with IP Address: %s - Invalid\n", ip) + logger.ControllerLog.Errorf("userAppApp response received with IP Address: %s - Invalid", ip) continue } validIps.IpAddresses = append(validIps.IpAddresses, ip) } - logger.ControllerLog.Debugf("RogueIPs [%v] received from UserAppApp", validIps.IpAddresses) + logger.ControllerLog.Debugf("rogueIPs [%v] received from userAppApp", validIps.IpAddresses) return validIps } func (userAppClient *UserAppService) GetRogueIPs(rogueIPChannel chan RogueIPs) { userAppServerApi := userAppClient.UserAppServiceUrl - logger.ControllerLog.Infoln("UserAppApp Url: ", userAppServerApi) + logger.ControllerLog.Infoln("userAppApp Url:", userAppServerApi) req, err := http.NewRequest(http.MethodGet, userAppServerApi, nil) if err != nil { - logger.ControllerLog.Errorln("An Error Occurred ", err) + logger.ControllerLog.Errorln("an error occurred", err) return } for { rsp, httpErr := sendHttpReqMsg(req) if httpErr != nil { - logger.ControllerLog.Errorf("Get Message [%v] returned error [%v] ", userAppServerApi, err.Error()) + logger.ControllerLog.Errorf("get message [%v] returned error [%+v]", userAppServerApi, err) time.Sleep(10 * time.Second) continue } @@ -216,9 +216,9 @@ func (userAppClient *UserAppService) GetRogueIPs(rogueIPChannel chan RogueIPs) { if rsp.Body != nil { err := json.NewDecoder(rsp.Body).Decode(&rogueIPs) if err != nil { - logger.ControllerLog.Errorln("UserAppApp response body decode failed: ", err) + logger.ControllerLog.Errorln("userAppApp response body decode failed:", err) } else { - logger.ControllerLog.Infoln("received rogueIPs from UserApp App: ", rogueIPs) + logger.ControllerLog.Infoln("received rogueIPs from userAppApp:", rogueIPs) ips := validateIPs(rogueIPs) if len(ips.IpAddresses) > 0 { // writing rogueIPs into channel @@ -226,7 +226,7 @@ func (userAppClient *UserAppService) GetRogueIPs(rogueIPChannel chan RogueIPs) { } } } else { - logger.ControllerLog.Infoln("Http Response Body from UserAppApp is empty") + logger.ControllerLog.Infoln("http response body from userAppApp is empty") } } @@ -238,12 +238,12 @@ func (rocClient *RocService) GetTargets() (names []Targets) { rocTargetsApi := rocClient.RocServiceUrl + "/aether-roc-api/targets" req, err := http.NewRequest(http.MethodGet, rocTargetsApi, nil) if err != nil { - logger.ControllerLog.Errorf("GetTargets Request Error Occurred %v", err) + logger.ControllerLog.Errorf("get targets request error occurred %v", err) return } rsp, httpErr := sendHttpReqMsgWithoutRetry(req) if httpErr != nil { - logger.ControllerLog.Errorf("Get Message [%v] returned error [%v] ", rocTargetsApi, httpErr.Error()) + logger.ControllerLog.Errorf("get message [%v] returned error [%v] ", rocTargetsApi, httpErr.Error()) return } @@ -251,15 +251,15 @@ func (rocClient *RocService) GetTargets() (names []Targets) { if rsp.Body != nil { err := json.NewDecoder(rsp.Body).Decode(&names) if err != nil { - logger.ControllerLog.Errorln("Unable to decode Targets: ", err) + logger.ControllerLog.Errorln("unable to decode Targets:", err) } else { - logger.ControllerLog.Infoln("GetTargets received from RoC: ", names) + logger.ControllerLog.Infoln("get targets received from RoC:", names) } } else { - logger.ControllerLog.Errorln("GetTargets Http Response Body is empty") + logger.ControllerLog.Errorln("get targets http response body is empty") } } else { - logger.ControllerLog.Errorln("GetTargets Http Response is empty") + logger.ControllerLog.Errorln("get targets http response is empty") } return } @@ -269,12 +269,12 @@ func (rocClient *RocService) DisableSimcard(targets []Targets, imsi string) { rocSiteApi := rocClient.RocServiceUrl + "/aether-roc-api/aether/v2.1.x/" + target.EnterpriseId + "/site" req, err := http.NewRequest(http.MethodGet, rocSiteApi, nil) if err != nil { - logger.ControllerLog.Errorf("GetSiteInfo Request Error Occurred %v", err) + logger.ControllerLog.Errorf("GetSiteInfo request error occurred %v", err) return } rsp, httpErr := sendHttpReqMsgWithoutRetry(req) if httpErr != nil { - logger.ControllerLog.Errorf("GetSiteInfo Message [%v] returned error [%v] ", rocSiteApi, httpErr.Error()) + logger.ControllerLog.Errorf("GetSiteInfo message [%v] returned error [%v] ", rocSiteApi, httpErr.Error()) continue } var siteInfo []SiteInfo @@ -292,13 +292,13 @@ func (rocClient *RocService) DisableSimcard(targets []Targets, imsi string) { logger.ControllerLog.Warnf("error reading body: %v", err) } - logger.ControllerLog.Infof("SimDetails Received from RoC: %s\n", string(b)) + logger.ControllerLog.Infof("SimDetails received from RoC: %s", string(b)) } else { - logger.ControllerLog.Errorln("GetSiteInfo Http Response Body is empty") + logger.ControllerLog.Errorln("GetSiteInfo http response body is empty") continue } } else { - logger.ControllerLog.Errorln("GetSiteInfo Http Response is empty") + logger.ControllerLog.Errorln("GetSiteInfo http response is empty") continue } @@ -307,7 +307,7 @@ func (rocClient *RocService) DisableSimcard(targets []Targets, imsi string) { for _, simCard := range siteInfo.SimCardDetails { imsi = strings.TrimPrefix(imsi, "imsi-") if simCard.Imsi == imsi { - logger.ControllerLog.Infof("SimCard %v Details Found in site [%v]\n", imsi, siteInfo.SiteId) + logger.ControllerLog.Infof("SimCard %v details found in site [%v]", imsi, siteInfo.SiteId) rocDisableSimCard = &simCard break } @@ -322,8 +322,8 @@ func (rocClient *RocService) DisableSimcard(targets []Targets, imsi string) { } reqMsgBody := bytes.NewBuffer(b) - logger.ControllerLog.Debugln("Rest API to disable IMSI: ", rocDisableImsiApi) - logger.ControllerLog.Debugln("Post Msg Body:", reqMsgBody) + logger.ControllerLog.Debugln("rest API to disable imsi:", rocDisableImsiApi) + logger.ControllerLog.Debugln("post msg body:", reqMsgBody) req, err := http.NewRequest(http.MethodPost, rocDisableImsiApi, reqMsgBody) if err != nil { @@ -333,14 +333,14 @@ func (rocClient *RocService) DisableSimcard(targets []Targets, imsi string) { req.Header.Set("Content-Type", "application/json; charset=utf-8") _, httpErr := sendHttpReqMsgWithoutRetry(req) if httpErr != nil { - logger.ControllerLog.Errorf("Post Message [%v] returned error [%v] ", rocDisableImsiApi, httpErr.Error()) + logger.ControllerLog.Errorf("post message [%v] returned error [%v]", rocDisableImsiApi, httpErr.Error()) } return } } } - logger.ControllerLog.Warnf("Imsi details not found in Targets and SiteInfo: [%v]", imsi) + logger.ControllerLog.Warnf("imsi details not found in Targets and SiteInfo: [%v]", imsi) } func RogueIPHandler(rogueIPChannel chan RogueIPs) { @@ -355,15 +355,15 @@ func RogueIPHandler(rogueIPChannel chan RogueIPs) { // get IP to imsi mapping from metricfunc subscriberInfo, err := metricdata.GetSubscriberImsiFromIpAddr(ipaddr) if err != nil { - logger.ControllerLog.Errorln("Subscriber details doesn't exist with imsi ", err) + logger.ControllerLog.Errorln("subscriber details doesn't exist with imsi", err) continue } - logger.ControllerLog.Infof("Subscriber Imsi [%v] of the IP: [%v]", subscriberInfo.Imsi, ipaddr) + logger.ControllerLog.Infof("subscriber Imsi [%v] of the IP: [%v]", subscriberInfo.Imsi, ipaddr) // get enterprises or targets from ROC targets := rocClient.GetTargets() if len(targets) == 0 { - logger.ControllerLog.Errorln("GetTargets returns nil") + logger.ControllerLog.Errorln("get targets returns nil") } else { // get siteinfo from ROC rocClient.DisableSimcard(targets, subscriberInfo.Imsi) diff --git a/internal/promclient/promclient.go b/internal/promclient/promclient.go index ed73c86..a33c14d 100644 --- a/internal/promclient/promclient.go +++ b/internal/promclient/promclient.go @@ -36,7 +36,9 @@ func StartPrometheusClient(cfg *config.ServerAddr) { logger.PromLog.Debugf("prometheus server initialised on address [%v] port [%v]", cfg.Addr, cfg.Port) HTTPAddr := fmt.Sprintf(":%d", cfg.Port) http.Handle("/metrics", promhttp.Handler()) - http.ListenAndServe(HTTPAddr, nil) + if err := http.ListenAndServe(HTTPAddr, nil); err != nil { + logger.PromLog.Errorf("failed to start http server: %v", err) + } } func initPromStats() *PromStats { @@ -98,18 +100,27 @@ func (ps *PromStats) register() error { // PushCoreSubData increments message level stats func PushCoreSubData(imsi, ip_addr, state, smf_ip, dnn, slice, upf string) { - logger.PromLog.Debugf("adding subscriber data [%v, %v, %v, %v, %v, %v, %v]", imsi, ip_addr, state, smf_ip, dnn, slice, upf) + logger.PromLog.Debugf( + "adding subscriber data [%v, %v, %v, %v, %v, %v, %v]", + imsi, ip_addr, state, smf_ip, dnn, slice, upf, + ) promStats.coreSub.WithLabelValues(imsi, "", state, smf_ip, dnn, slice, upf).Inc() } func DeleteCoreSubData(imsi, ip_addr, state, smf_ip, dnn, slice, upf string) { - logger.PromLog.Debugf("deleting subscriber data [%v, %v, %v, %v, %v, %v, %v]", imsi, ip_addr, state, smf_ip, dnn, slice, upf) + logger.PromLog.Debugf( + "deleting subscriber data [%v, %v, %v, %v, %v, %v, %v]", + imsi, ip_addr, state, smf_ip, dnn, slice, upf, + ) promStats.coreSub.DeleteLabelValues(imsi, "", state, smf_ip, dnn, slice, upf) } // SetSessStats maintains Session level stats func SetSmfSessStats(smfIp, slice, dnn, upf string, count uint64) { - logger.PromLog.Debugf("setting smf session count [%v] with labels [smfIp:%v, slice:%v, dnn:%v, upf:%v]", count, smfIp, slice, dnn, upf) + logger.PromLog.Debugf( + "setting smf session count [%v] with labels [smfIp:%v, slice:%v, dnn:%v, upf:%v]", + count, smfIp, slice, dnn, upf, + ) promStats.smfSessions.WithLabelValues("", "", "", "").Set(float64(count)) } diff --git a/metricfunc.go b/metricfunc.go index 9f3a8e9..2e38e77 100644 --- a/metricfunc.go +++ b/metricfunc.go @@ -32,7 +32,7 @@ func init() { func main() { // Read provided config - cfgFilePtr := flag.String("metrics", "../../config/config.yaml", "is a config file") + cfgFilePtr := flag.String("cfg", "/opt/config.yaml", "metricfunc config file") flag.Parse() logger.AppLog.Infof("Metricfunction has started with configuration file [%v]", *cfgFilePtr)