Update logging interface

Change-Id: I51bc8405cfe02b7bb2d94307d6e7ecb720c77d54
Signed-off-by: Abukar Mohamed <abukar.mohamed@nokia.com>
diff --git a/Dockerfile b/Dockerfile
index 142c876..c20bde2 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -28,6 +28,7 @@
 # packages
 #
 RUN apt-get update -y && \
+    apt-get upgrade -y && \
     apt-get install -y \
     build-essential \
     apt-utils \
@@ -54,16 +55,6 @@
 
 ENV PATH="/usr/local/go/bin:${PATH}"
 
-#
-# rancodev libs
-#
-RUN mkdir -p /opt/build \
-    && cd /opt/build && git clone https://gerrit.o-ran-sc.org/r/ric-plt/lib/rmr \
-    && cd rmr/; mkdir build; cd build; cmake ..; make install \
-    && cd /opt/build && git clone https://gerrit.o-ran-sc.org/r/com/log \
-    && cd log/ ; ./autogen.sh ; ./configure ; make ; make install \
-    && ldconfig
-
 COPY build/user_entrypoint.sh /
 
 RUN chmod +x /user_entrypoint.sh
diff --git a/cmd/appmgr/api.go b/cmd/appmgr/api.go
index 8450d02..2de8b05 100755
--- a/cmd/appmgr/api.go
+++ b/cmd/appmgr/api.go
@@ -57,10 +57,11 @@
 		{"POST", "/ric/v1/config", m.createConfig},
 		{"PUT", "/ric/v1/config", m.updateConfig},
 		{"DELETE", "/ric/v1/config", m.deleteConfig},
+		{"DELETE", "/ric/v1/config/{name}", m.deleteSingleConfig},
 	}
 
 	for _, resource := range resources {
-		handler := Logger(resource.HandlerFunc)
+		handler := LogRestRequests(resource.HandlerFunc)
 		//handler = m.serviceChecker(handler)
 		m.router.Methods(resource.Method).Path(resource.Url).Handler(handler)
 	}
@@ -139,7 +140,7 @@
 			return
 		}
 	}
-	mdclog(MdclogErr, "Xapp instance not found - url="+r.URL.RequestURI())
+	Logger.Error("Xapp instance not found - url=%s", r.URL.RequestURI())
 
 	respondWithError(w, http.StatusNotFound, "Xapp instance not found")
 }
@@ -156,14 +157,14 @@
 
 func (m *XappManager) deployXapp(w http.ResponseWriter, r *http.Request) {
 	if r.Body == nil {
-		mdclog(MdclogErr, "No xapp data found in request body - url="+r.URL.RequestURI())
+		Logger.Error("No xapp data found in request body - url=%s", r.URL.RequestURI())
 		respondWithError(w, http.StatusMethodNotAllowed, "No xapp data!")
 		return
 	}
 
 	var cm XappDeploy
 	if err := json.NewDecoder(r.Body).Decode(&cm); err != nil {
-		mdclog(MdclogErr, "Invalid xapp data in request body - url="+r.URL.RequestURI())
+		Logger.Error("Invalid xapp data in request body - url=%s", r.URL.RequestURI())
 		respondWithError(w, http.StatusMethodNotAllowed, "Invalid xapp data!")
 		return
 	}
@@ -207,7 +208,7 @@
 		if s, ok := m.sd.Get(id); ok {
 			respondWithJSON(w, http.StatusOK, s)
 		} else {
-			mdclog(MdclogErr, "Subscription not found - url="+r.URL.RequestURI())
+			Logger.Error("Subscription not found - url=%s", r.URL.RequestURI())
 			respondWithError(w, http.StatusNotFound, "Subscription not found")
 		}
 	}
@@ -218,7 +219,7 @@
 		if _, ok := m.sd.Delete(id); ok {
 			respondWithJSON(w, http.StatusNoContent, nil)
 		} else {
-			mdclog(MdclogErr, "Subscription not found - url="+r.URL.RequestURI())
+			Logger.Error("Subscription not found - url=%s", r.URL.RequestURI())
 			respondWithError(w, http.StatusNotFound, "Subscription not found")
 		}
 	}
@@ -227,7 +228,7 @@
 func (m *XappManager) addSubscription(w http.ResponseWriter, r *http.Request) {
 	var req SubscriptionReq
 	if r.Body == nil || json.NewDecoder(r.Body).Decode(&req) != nil {
-		mdclog(MdclogErr, "Invalid request payload - url="+r.URL.RequestURI())
+		Logger.Error("Invalid request payload - url=%s", r.URL.RequestURI())
 		respondWithError(w, http.StatusMethodNotAllowed, "Invalid request payload")
 		return
 	}
@@ -240,7 +241,7 @@
 	if id, ok := getResourceId(r, w, "id"); ok == true {
 		var req SubscriptionReq
 		if r.Body == nil || json.NewDecoder(r.Body).Decode(&req) != nil {
-			mdclog(MdclogErr, "Invalid request payload - url="+r.URL.RequestURI())
+			Logger.Error("Invalid request payload - url=%s", r.URL.RequestURI())
 			respondWithError(w, http.StatusMethodNotAllowed, "Invalid request payload")
 			return
 		}
@@ -249,7 +250,7 @@
 		if s, ok := m.sd.Update(id, req); ok {
 			respondWithJSON(w, http.StatusOK, s)
 		} else {
-			mdclog(MdclogErr, "Subscription not found - url="+r.URL.RequestURI())
+			Logger.Error("Subscription not found - url=%s", r.URL.RequestURI())
 			respondWithError(w, http.StatusNotFound, "Subscription not found")
 		}
 	}
@@ -258,7 +259,7 @@
 func (m *XappManager) notifyClients() {
 	xapps, err := m.helm.StatusAll()
 	if err != nil {
-		mdclog(MdclogInfo, "Couldn't fetch xapps status information"+err.Error())
+		Logger.Info("Couldn't fetch xapps status information: %v", err.Error())
 		return
 	}
 
@@ -284,7 +285,7 @@
 		}
 		return
 	}
-	respondWithJSON(w, http.StatusCreated, nil)
+	respondWithJSON(w, http.StatusCreated, c.Metadata)
 }
 
 func (m *XappManager) updateConfig(w http.ResponseWriter, r *http.Request) {
@@ -297,11 +298,21 @@
 		if err.Error() != "Validation failed!" {
 			respondWithError(w, http.StatusInternalServerError, err.Error())
 		} else {
-			respondWithJSON(w, http.StatusUnprocessableEntity, errList)
+			respondWithJSON(w, http.StatusInternalServerError, errList)
 		}
 		return
 	}
-	respondWithJSON(w, http.StatusOK, nil)
+	respondWithJSON(w, http.StatusOK, c.Metadata)
+}
+
+func (m *XappManager) deleteSingleConfig(w http.ResponseWriter, r *http.Request) {
+	xappName, ok := getResourceId(r, w, "name")
+	if ok != true {
+		return
+	}
+
+	md := ConfigMetadata{Name: xappName, Namespace: m.cm.GetNamespace(""), ConfigName: xappName + "-appconfig"}
+	m.delConfig(w, XAppConfig{Metadata: md})
 }
 
 func (m *XappManager) deleteConfig(w http.ResponseWriter, r *http.Request) {
@@ -310,11 +321,15 @@
 		return
 	}
 
+	m.delConfig(w, c)
+}
+
+func (m *XappManager) delConfig(w http.ResponseWriter, c XAppConfig) {
 	if _, err := m.cm.DeleteConfigMap(c); err != nil {
 		respondWithError(w, http.StatusInternalServerError, err.Error())
 		return
 	}
-	respondWithJSON(w, http.StatusNotFound, nil)
+	respondWithJSON(w, http.StatusNoContent, nil)
 }
 
 // Helper functions
@@ -333,7 +348,7 @@
 
 func getResourceId(r *http.Request, w http.ResponseWriter, pattern string) (id string, ok bool) {
 	if id, ok = mux.Vars(r)[pattern]; ok != true {
-		mdclog(MdclogErr, "Couldn't resolve name/id from the request URL")
+		Logger.Error("Couldn't resolve name/id from the request URL")
 		respondWithError(w, http.StatusMethodNotAllowed, "Couldn't resolve name/id from the request URL")
 		return
 	}
@@ -342,7 +357,7 @@
 
 func parseConfig(w http.ResponseWriter, r *http.Request, req *XAppConfig) error {
 	if r.Body == nil || json.NewDecoder(r.Body).Decode(&req) != nil {
-		mdclog(MdclogErr, "Invalid request payload - url="+r.URL.RequestURI())
+		Logger.Error("Invalid request payload - url=%s", r.URL.RequestURI())
 		respondWithError(w, http.StatusMethodNotAllowed, "Invalid request payload")
 		return errors.New("Invalid payload")
 	}
diff --git a/cmd/appmgr/api_test.go b/cmd/appmgr/api_test.go
index 89e4a08..109f6e9 100755
--- a/cmd/appmgr/api_test.go
+++ b/cmd/appmgr/api_test.go
@@ -69,6 +69,7 @@
 
 // Test cases
 func TestMain(m *testing.M) {
+	Logger = NewLogger("xapp-manager")
 	loadConfig()
 
 	xapp = Xapp{}
@@ -185,7 +186,7 @@
 	req, _ := http.NewRequest("DELETE", "/ric/v1/config", bytes.NewBuffer(payload))
 	response := executeRequest(req)
 
-	checkResponseCode(t, http.StatusNotFound, response.Code)
+	checkResponseCode(t, http.StatusNoContent, response.Code)
 }
 
 // Error handling
diff --git a/cmd/appmgr/db.go b/cmd/appmgr/db.go
index 723fa10..97865c2 100755
--- a/cmd/appmgr/db.go
+++ b/cmd/appmgr/db.go
@@ -40,7 +40,7 @@
 		if _, err := d.session.GetAll(); err == nil {
 			return
 		}
-		mdclog(MdclogErr, "Database connection not ready, waiting ...")
+		Logger.Error("Database connection not ready, waiting ...")
 		time.Sleep(time.Duration(5 * time.Second))
 	}
 }
@@ -51,12 +51,12 @@
 
 		data, err := json.Marshal(s.req)
 		if err != nil {
-			mdclog(MdclogErr, "json.marshal failed: "+err.Error())
+			Logger.Error("json.marshal failed: %v ", err.Error())
 			return
 		}
 
 		if err := d.session.Set(s.req.Id, data); err != nil {
-			mdclog(MdclogErr, "DB.session.Set failed: "+err.Error())
+			Logger.Error("DB.session.Set failed: %v ", err.Error())
 		}
 	}
 }
@@ -66,20 +66,20 @@
 
 	keys, err := d.session.GetAll()
 	if err != nil {
-		mdclog(MdclogErr, "DB.session.GetAll failed: "+err.Error())
+		Logger.Error("DB.session.GetAll failed: %v ", err.Error())
 		return
 	}
 
 	for _, key := range keys {
 		value, err := d.session.Get([]string{key})
 		if err != nil {
-			mdclog(MdclogErr, "DB.session.Get failed: "+err.Error())
+			Logger.Error("DB.session.Get failed: %v ", err.Error())
 			return
 		}
 
 		var item SubscriptionReq
 		if err = json.Unmarshal([]byte(value[key].(string)), &item); err != nil {
-			mdclog(MdclogErr, "json.Unmarshal failed: "+err.Error())
+			Logger.Error("json.Unmarshal failed: %v ", err.Error())
 			return
 		}
 
diff --git a/cmd/appmgr/desc.go b/cmd/appmgr/desc.go
index ac1d0c8..d4493be 100755
--- a/cmd/appmgr/desc.go
+++ b/cmd/appmgr/desc.go
@@ -65,13 +65,14 @@
 }
 
 func (cm *ConfigMap) UploadConfig() (cfg []XAppConfig) {
+	ns := cm.GetNamespace("")
 	for _, name := range cm.GetNamesFromHelmRepo() {
 		if name == "appmgr" {
 			continue
 		}
 
 		c := XAppConfig{
-			Metadata: ConfigMetadata{Name: name, Namespace: "ricxapp", ConfigName: name + "-appconfig"},
+			Metadata: ConfigMetadata{Name: name, Namespace: ns, ConfigName: name + "-appconfig"},
 		}
 
 		err := cm.ReadSchema(name, &c)
@@ -79,7 +80,7 @@
 			continue
 		}
 
-		err = cm.ReadConfigMap(c.Metadata.ConfigName, "ricxapp", &c.Configuration)
+		err = cm.ReadConfigMap(c.Metadata.ConfigName, ns, &c.Configuration)
 		if err != nil {
 			log.Println("No active configMap found, using default!")
 		}
@@ -291,7 +292,8 @@
 func (cm *ConfigMap) GetMessages(name string) (msgs MessageTypes) {
 	log.Println("Fetching tx/rx messages for: ", name)
 
-	args := fmt.Sprintf("get configmap -o jsonpath='{.data.config-file\\.json}' -n ricxapp %s-appconfig", name)
+	ns := cm.GetNamespace("")
+	args := fmt.Sprintf("get configmap -o jsonpath='{.data.config-file\\.json}' -n %s %s-appconfig", ns, name)
 	out, err := KubectlExec(args)
 	if err != nil {
 		return
@@ -313,3 +315,16 @@
 
 	return
 }
+
+func (cm *ConfigMap) GetNamespace(ns string) string {
+	if ns != "" {
+		return ns
+	}
+
+	ns = viper.GetString("xapp.namespace")
+	if ns == "" {
+		ns = "ricxapp"
+	}
+	return ns
+}
+
diff --git a/cmd/appmgr/desc_test.go b/cmd/appmgr/desc_test.go
index f553c38..bd4a3f3 100755
--- a/cmd/appmgr/desc_test.go
+++ b/cmd/appmgr/desc_test.go
@@ -66,6 +66,10 @@
 type MockedConfigMapper struct {
 }
 
+func (cm *MockedConfigMapper) ReadSchema(name string, c *XAppConfig) (err error) {
+	return
+}
+
 func (cm *MockedConfigMapper) UploadConfig() (cfg []XAppConfig) {
 	return
 }
@@ -74,15 +78,19 @@
 	return
 }
 
-func (cm *MockedConfigMapper) UpdateConfigMap(r XAppConfig) (errList []CMError, err error){
+func (cm *MockedConfigMapper) GetConfigMap(m XappDeploy, c *interface{}) (err error) {
 	return
 }
 
-func (cm *MockedConfigMapper) DeleteConfigMap(r XAppConfig) (c interface{}, err error){
+func (cm *MockedConfigMapper) UpdateConfigMap(r XAppConfig) (errList []CMError, err error) {
 	return
 }
 
-func (cm *MockedConfigMapper) PurgeConfigMap(m XappDeploy) (c interface{}, err error){
+func (cm *MockedConfigMapper) DeleteConfigMap(r XAppConfig) (c interface{}, err error) {
+	return
+}
+
+func (cm *MockedConfigMapper) PurgeConfigMap(m XappDeploy) (c interface{}, err error) {
 	return
 }
 
@@ -106,6 +114,10 @@
 	return
 }
 
+func (cm *MockedConfigMapper) GetNamespace(ns string) (n string) {
+	return
+}
+
 // Test cases
 func TestGetMessages(t *testing.T) {
 	cm := ConfigMap{}
@@ -124,6 +136,18 @@
 	}
 }
 
+func TestHelmNamespace(t *testing.T) {
+	cm := ConfigMap{}
+
+	if cm.GetNamespace("pltxapp") != "pltxapp" {
+        t.Errorf("getNamespace failed!")
+	}
+
+    if cm.GetNamespace("") != "ricxapp" {
+        t.Errorf("getNamespace failed!")
+	}
+}
+
 func TestFetchChartFails(t *testing.T) {
 	cm := ConfigMap{}
 
diff --git a/cmd/appmgr/helm.go b/cmd/appmgr/helm.go
index 578dcf0..a3785c8 100755
--- a/cmd/appmgr/helm.go
+++ b/cmd/appmgr/helm.go
@@ -48,7 +48,7 @@
 	for i := 0; i < viper.GetInt("helm.retry"); i++ {
 		err = cmd.Run()
 		if err != nil {
-			mdclog(MdclogErr, formatLog("Command failed, retrying", args, err.Error()+stderr.String()))
+			Logger.Error("Command '%s' failed with error: %v, retrying", args, err.Error()+stderr.String())
 			time.Sleep(time.Duration(2) * time.Second)
 			continue
 		}
@@ -56,7 +56,7 @@
 	}
 
 	if err == nil && !strings.HasSuffix(os.Args[0], ".test") {
-		mdclog(MdclogDebug, formatLog("command success", stdout.String(), ""))
+		Logger.Info("command success: %s", stdout.String())
 		return stdout.Bytes(), nil
 	}
 
@@ -82,19 +82,19 @@
 
 	for {
 		if _, err := h.Init(); err == nil {
-			mdclog(MdclogDebug, formatLog("Helm init done successfully!", "", ""))
+			Logger.Info("Helm init done successfully!")
 			break
 		}
-		mdclog(MdclogErr, formatLog("helm init failed, retyring ...", "", ""))
+		Logger.Error("helm init failed, retyring ...")
 		time.Sleep(time.Duration(10) * time.Second)
 	}
 
 	for {
 		if _, err := h.AddRepo(); err == nil {
-			mdclog(MdclogDebug, formatLog("Helm repo added successfully", "", ""))
+			Logger.Info("Helm repo added successfully")
 			break
 		}
-		mdclog(MdclogErr, formatLog("Helm repo addition failed, retyring ...", "", ""))
+		Logger.Error("Helm repo addition failed, retyring ...")
 		time.Sleep(time.Duration(10) * time.Second)
 	}
 
@@ -119,7 +119,7 @@
 	// Get helm repo user name and password from files mounted by secret object
 	credFile, err := ioutil.ReadFile(viper.GetString("helm.helm-username-file"))
 	if err != nil {
-		mdclog(MdclogErr, formatLog("helm_repo_username ReadFile failed", "", err.Error()))
+		Logger.Error("helm_repo_username ReadFile failed: %v", err.Error())
 		return
 	}
 
@@ -127,7 +127,7 @@
 
 	credFile, err = ioutil.ReadFile(viper.GetString("helm.helm-password-file"))
 	if err != nil {
-		mdclog(MdclogErr, formatLog("helm_repo_password ReadFile failed", "", err.Error()))
+		Logger.Error("helm_repo_password ReadFile failed: %v", err.Error())
 		return
 	}
 
@@ -149,7 +149,7 @@
 	}
 
 	var cm interface{}
-	m.Namespace = getNamespace(m.Namespace)
+	m.Namespace = h.cm.GetNamespace(m.Namespace)
 
 	if err = h.cm.GetConfigMap(m, &cm); err != nil {
 		out, err = h.Run(getInstallArgs(m, false))
@@ -180,7 +180,7 @@
 func (h *Helm) Status(name string) (xapp Xapp, err error) {
 	out, err := h.Run(strings.Join([]string{"status ", name}, ""))
 	if err != nil {
-		mdclog(MdclogErr, formatLog("Getting xapps status", "", err.Error()))
+		Logger.Error("Getting xapps status: %v", err.Error())
 		return
 	}
 
@@ -190,7 +190,7 @@
 func (h *Helm) StatusAll() (xapps []Xapp, err error) {
 	xappNameList, err := h.List()
 	if err != nil {
-		mdclog(MdclogErr, formatLog("Helm list failed", "", err.Error()))
+		Logger.Error("Helm list failed: %v", err.Error())
 		return
 	}
 
@@ -198,10 +198,10 @@
 }
 
 func (h *Helm) List() (names []string, err error) {
-	ns := getNamespace("")
+	ns := h.cm.GetNamespace("")
 	out, err := h.Run(strings.Join([]string{"list --all --output yaml --namespace=", ns}, ""))
 	if err != nil {
-		mdclog(MdclogErr, formatLog("Listing deployed xapps failed", "", err.Error()))
+		Logger.Error("Listing deployed xapps failed: %v", err.Error())
 		return
 	}
 
@@ -211,7 +211,7 @@
 func (h *Helm) Delete(name string) (xapp Xapp, err error) {
 	xapp, err = h.Status(name)
 	if err != nil {
-		mdclog(MdclogErr, formatLog("Fetching xapp status failed", "", err.Error()))
+		Logger.Error("Fetching xapp status failed: %v", err.Error())
 		return
 	}
 
@@ -232,7 +232,7 @@
 
 // Helper functions
 func (h *Helm) GetVersion(name string) (version string) {
-	ns := getNamespace("")
+	ns := h.cm.GetNamespace("")
 	out, err := h.Run(strings.Join([]string{"list --output yaml --namespace=", ns, " ", name}, ""))
 	if err != nil {
 		return
@@ -325,6 +325,11 @@
 	xapps = []Xapp{}
 
 	for _, name := range names {
+		err := h.cm.ReadSchema(name, &XAppConfig{})
+		if err != nil {
+			continue
+		}
+
 		x, err := h.Status(name)
 		if err == nil {
 			xapps = append(xapps, x)
@@ -340,24 +345,12 @@
 	port := viper.GetString("helm.tiller-port")
 
 	if err = os.Setenv("HELM_HOST", service+"."+namespace+":"+port); err != nil {
-		mdclog(MdclogErr, formatLog("Tiller Env Setting Failed", "", err.Error()))
+		Logger.Error("Tiller Env Setting Failed: %v", err.Error())
 	}
 
 	return err
 }
 
-func getNamespace(namespace string) string {
-	if namespace != "" {
-		return namespace
-	}
-
-	ns := viper.GetString("xapp.namespace")
-	if ns == "" {
-		ns = "ricxapp"
-	}
-	return ns
-}
-
 func getInstallArgs(x XappDeploy, cmOverride bool) (args string) {
 	args = args + " --namespace=" + x.Namespace
 
@@ -380,7 +373,3 @@
 	rname := viper.GetString("helm.repo-name")
 	return fmt.Sprintf("install %s/%s --name=%s %s", rname, x.Name, x.Name, args)
 }
-
-func formatLog(text string, args string, err string) string {
-	return fmt.Sprintf("Helm: %s: args=%s err=%s\n", text, args, err)
-}
diff --git a/cmd/appmgr/helm_test.go b/cmd/appmgr/helm_test.go
index c3ac3c5..b3ff348 100755
--- a/cmd/appmgr/helm_test.go
+++ b/cmd/appmgr/helm_test.go
@@ -99,16 +99,6 @@
     }
 }
 
-func TestHelmNamespace(t *testing.T) {
-    if getNamespace("pltxapp") != "pltxapp" {
-        t.Errorf("getNamespace failed!")
-	}
-
-    if getNamespace("") != "ricxapp" {
-        t.Errorf("getNamespace failed!")
-	}
-}
-
 func TestAddTillerEnv(t *testing.T) {
     if addTillerEnv() != nil {
         t.Errorf("TestAddTillerEnv failed!")
@@ -116,7 +106,7 @@
 }
 
 func TestGetInstallArgs(t *testing.T) {
-	x := XappDeploy{Name: "dummy-xapp"}
+	x := XappDeploy{Name: "dummy-xapp", Namespace: "ricxapp"}
 
 	expectedArgs := "install helm-repo/dummy-xapp --name=dummy-xapp  --namespace=ricxapp"
 	if args := getInstallArgs(x, false); args != expectedArgs {
@@ -124,19 +114,19 @@
 	}
 
 	x.ImageRepo = "localhost:5000"
-	expectedArgs = expectedArgs + " --set image.repository=" + "localhost:5000"
+	expectedArgs = expectedArgs + " --set global.repository=" + "localhost:5000"
 	if args := getInstallArgs(x, false); args != expectedArgs {
         t.Errorf("TestGetInstallArgs failed: expected %v, got %v", expectedArgs, args)
 	}
 
 	x.ServiceName = "xapp"
-	expectedArgs = expectedArgs + " --set service.name=" + "xapp"
+	expectedArgs = expectedArgs + " --set ricapp.service.name=" + "xapp"
 	if args := getInstallArgs(x, false); args != expectedArgs {
         t.Errorf("TestGetInstallArgs failed: expected %v, got %v", expectedArgs, args)
 	}
 
 	x.ServiceName = "xapp"
-	expectedArgs = expectedArgs + " --set appconfig.override=true"
+	expectedArgs = expectedArgs + " --set ricapp.appconfig.override=dummy-xapp-appconfig"
 	if args := getInstallArgs(x, true); args != expectedArgs {
         t.Errorf("TestGetInstallArgs failed: expected %v, got %v", expectedArgs, args)
 	}
diff --git a/cmd/appmgr/logger.go b/cmd/appmgr/logger.go
index 877bcbe..b8a7475 100755
--- a/cmd/appmgr/logger.go
+++ b/cmd/appmgr/logger.go
@@ -19,38 +19,54 @@
 
 package main
 
-/*
-#cgo CFLAGS: -I/usr/local/include
-#cgo LDFLAGS: -lmdclog
-#
-#include <mdclog/mdclog.h>
-void xAppMgr_mdclog_write(mdclog_severity_t severity, const char *msg) {
-     mdclog_write(severity, "%s", msg);
-}
-*/
-import "C"
-
 import (
-	"fmt"
 	"net/http"
 	"time"
+	mdclog "gerrit.o-ran-sc.org/r/com/golog"
 )
 
-func mdclog(severity C.mdclog_severity_t, msg string) {
-	msg = fmt.Sprintf("%s:: %s ", time.Now().Format("2019-01-02 15:04:05"), msg)
-
-	C.mdclog_mdc_add(C.CString("XM"), C.CString("1.0.1"))
-	C.xAppMgr_mdclog_write(severity, C.CString(msg))
+type Log struct {
+	logger *mdclog.MdcLogger
 }
 
-func mdclogSetLevel(severity C.mdclog_severity_t) {
-	C.mdclog_level_set(severity)
+func NewLogger(name string) *Log {
+	l, _ := mdclog.InitLogger(name)
+	return &Log{
+		logger: l,
+	}
 }
 
-func Logger(inner http.Handler) http.Handler {
+func (l *Log) SetLevel(level int) {
+	l.logger.LevelSet(mdclog.Level(level))
+}
+
+func (l *Log) SetMdc(key string, value string) {
+	l.logger.MdcAdd(key, value)
+}
+
+func (l *Log) Error(pattern string, args ...interface{}) {
+	l.SetMdc("time", time.Now().Format("2019-01-02 15:04:05"))
+	l.logger.Error(pattern, args...)
+}
+
+func (l *Log) Warn(pattern string, args ...interface{}) {
+	l.SetMdc("time", time.Now().Format("2019-01-02 15:04:05"))
+	l.logger.Warning(pattern, args...)
+}
+
+func (l *Log) Info(pattern string, args ...interface{}) {
+	l.SetMdc("time", time.Now().Format("2019-01-02 15:04:05"))
+	l.logger.Info(pattern, args...)
+}
+
+func (l *Log) Debug(pattern string, args ...interface{}) {
+	l.SetMdc("time", time.Now().Format("2019-01-02 15:04:05"))
+	l.logger.Debug(pattern, args...)
+}
+
+func LogRestRequests(inner http.Handler) http.Handler {
 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		inner.ServeHTTP(w, r)
-		s := fmt.Sprintf("Logger: method=%s url=%s", r.Method, r.URL.RequestURI())
-		mdclog(C.MDCLOG_DEBUG, s)
+		Logger.Info("Logger: method=%s url=%s", r.Method, r.URL.RequestURI())
 	})
 }
diff --git a/cmd/appmgr/main.go b/cmd/appmgr/main.go
index 9b9eebb..954f957 100755
--- a/cmd/appmgr/main.go
+++ b/cmd/appmgr/main.go
@@ -19,8 +19,10 @@
 
 package main
 
+var Logger *Log
+
 func main() {
-	mdclogSetLevel(MdclogDebug)
+	Logger = NewLogger("xapp-manager")
 
 	loadConfig()
 
diff --git a/cmd/appmgr/subscriptions.go b/cmd/appmgr/subscriptions.go
index 5728e5b..1db4c5a 100755
--- a/cmd/appmgr/subscriptions.go
+++ b/cmd/appmgr/subscriptions.go
@@ -22,7 +22,6 @@
 import (
 	"bytes"
 	"encoding/json"
-	"fmt"
 	"github.com/segmentio/ksuid"
 	"net/http"
 	"time"
@@ -44,7 +43,7 @@
 	sd.subscriptions.Set(key, Subscription{sr, resp})
 	sd.db.StoreSubscriptions(sd.subscriptions)
 
-	mdclog(MdclogInfo, fmt.Sprintf("Sub: New subscription added: key=%s value=%v", key, sr))
+	Logger.Info("Sub: New subscription added: key=%s value=%v", key, sr)
 	return
 }
 
@@ -59,7 +58,7 @@
 
 func (sd *SubscriptionDispatcher) Get(id string) (SubscriptionReq, bool) {
 	if v, found := sd.subscriptions.Get(id); found {
-		mdclog(MdclogInfo, fmt.Sprintf("Subscription id=%s found: %v", id, v.(Subscription).req))
+		Logger.Info("Subscription id=%s found: %v", id, v.(Subscription).req)
 
 		return v.(Subscription).req, found
 	}
@@ -68,7 +67,7 @@
 
 func (sd *SubscriptionDispatcher) Delete(id string) (SubscriptionReq, bool) {
 	if v, found := sd.subscriptions.Get(id); found {
-		mdclog(MdclogInfo, fmt.Sprintf("Subscription id=%s found: %v ... deleting", id, v.(Subscription).req))
+		Logger.Info("Subscription id=%s found: %v ... deleting", id, v.(Subscription).req)
 
 		sd.subscriptions.Remove(id)
 		sd.db.StoreSubscriptions(sd.subscriptions)
@@ -80,7 +79,7 @@
 
 func (sd *SubscriptionDispatcher) Update(id string, sr SubscriptionReq) (SubscriptionReq, bool) {
 	if s, found := sd.subscriptions.Get(id); found {
-		mdclog(MdclogInfo, fmt.Sprintf("Subscription id=%s found: %v ... updating", id, s.(Subscription).req))
+		Logger.Info("Subscription id=%s found: %v ... updating", id, s.(Subscription).req)
 
 		sr.Id = id
 		sd.subscriptions.Set(id, Subscription{sr, s.(Subscription).resp})
@@ -97,7 +96,7 @@
 
 func (sd *SubscriptionDispatcher) notifyClients(xapps []Xapp, et EventType) {
 	if len(xapps) == 0 || len(sd.subscriptions) == 0 {
-		mdclog(MdclogInfo, fmt.Sprintf("Nothing to publish [%d:%d]", len(xapps), len(sd.subscriptions)))
+		Logger.Info("Nothing to publish [%d:%d]", len(xapps), len(sd.subscriptions))
 		return
 	}
 
@@ -113,7 +112,7 @@
 
 	jsonData, err := json.Marshal(notif)
 	if err != nil {
-		mdclog(MdclogInfo, fmt.Sprintf("json.Marshal failed: %v", err))
+		Logger.Info("json.Marshal failed: %v", err)
 		return err
 	}
 
@@ -121,16 +120,16 @@
 	return sd.retry(s, func() error {
 		resp, err := http.Post(s.req.TargetUrl, "application/json", bytes.NewBuffer(jsonData))
 		if err != nil {
-			mdclog(MdclogInfo, fmt.Sprintf("Posting to subscription failed: %v", err))
+			Logger.Info("Posting to subscription failed: %v", err)
 			return err
 		}
 
 		if resp.StatusCode != http.StatusOK {
-			mdclog(MdclogInfo, fmt.Sprintf("Client returned error code: %d", resp.StatusCode))
+			Logger.Info("Client returned error code: %d", resp.StatusCode)
 			return err
 		}
 
-		mdclog(MdclogInfo, fmt.Sprintf("subscription to '%s' dispatched, response code: %d \n", s.req.TargetUrl, resp.StatusCode))
+		Logger.Info("subscription to '%s' dispatched, response code: %d", s.req.TargetUrl, resp.StatusCode)
 		return nil
 	})
 }
diff --git a/cmd/appmgr/types.go b/cmd/appmgr/types.go
index e32b62f..d452498 100755
--- a/cmd/appmgr/types.go
+++ b/cmd/appmgr/types.go
@@ -77,11 +77,13 @@
 	CreateConfigMap(r XAppConfig) (errList []CMError, err error)
 	UpdateConfigMap(r XAppConfig) (errList []CMError, err error)
 	DeleteConfigMap(r XAppConfig) (cm interface{}, err error)
+	ReadSchema(name string, c *XAppConfig) (err error)
 	PurgeConfigMap(m XappDeploy) (cm interface{}, err error)
 	RestoreConfigMap(m XappDeploy, cm interface{}) (err error)
 	ReadConfigMap(name string, ns string, c *interface{}) (err error)
 	ApplyConfigMap(r XAppConfig, action string) (err error)
 	GetMessages(name string) (msgs MessageTypes)
+	GetNamespace(ns string) string
 }
 
 type Helmer interface {
diff --git a/go.mod b/go.mod
index 19c1062..6a22825 100644
--- a/go.mod
+++ b/go.mod
@@ -3,6 +3,7 @@
 go 1.12
 
 require (
+	gerrit.o-ran-sc.org/r/com/golog v0.0.1
 	gerrit.oran-osc.org/r/ric-plt/sdlgo v0.0.0
 	github.com/BurntSushi/toml v0.3.1 // indirect
 	github.com/fsnotify/fsnotify v1.4.7
@@ -17,3 +18,5 @@
 )
 
 replace gerrit.oran-osc.org/r/ric-plt/sdlgo => gerrit.oran-osc.org/r/ric-plt/sdlgo.git v0.0.1
+
+replace gerrit.o-ran-sc.org/r/com/golog => gerrit.o-ran-sc.org/r/com/golog.git v0.0.1
diff --git a/go.sum b/go.sum
index 46361f4..e0539a4 100644
--- a/go.sum
+++ b/go.sum
@@ -1,3 +1,6 @@
+gerrit.o-ran-sc.org/r/com/golog.git v0.0.1 h1:9RfO/Whehaaq5KiJTT7s+YOzmi9mT1C3HktfhwwMEmw=
+gerrit.o-ran-sc.org/r/com/golog.git v0.0.1/go.mod h1:b8YB31U8/4iRpABioeSzGi/YMzOQ/Zq7hrJmmXKqlJk=
+gerrit.o-ran-sc.org/r/ric-plt/sdlgo.git v0.1.1/go.mod h1:2Y8gw2jqj9urI8VFqFQn7BX0J3A852+YrXVV9V8gOt4=
 gerrit.oran-osc.org/r/ric-plt/sdlgo.git v0.0.1 h1:l2dl31r++3xhgCumTzwvuo0/F415eqU4aFk/uDQ4WnM=
 gerrit.oran-osc.org/r/ric-plt/sdlgo.git v0.0.1/go.mod h1:LVhkNS82IofJTBK/VYPKiYed9MG/3OFwvWC6MGSDw1w=
 github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=