[ISSUE-70861663] add tracking with request id in debug mode (#33)

* [ISSUE-70861663] add tracking with request id in debug mode

* [ISSUE-70861663] address comments

* [ISSUE-70861663] improve log

* [ISSUE-70861663] address comments
diff --git a/accessEntity/api.go b/accessEntity/api.go
index fb49fca..9a37200 100644
--- a/accessEntity/api.go
+++ b/accessEntity/api.go
@@ -63,6 +63,8 @@
 	StatusExpired  = "EXPIRED"
 )
 
+const headerRequestId = "X-Gateway-Request-Id"
+
 var (
 	Identifiers = map[string]bool{
 		"appid":          true,
@@ -127,6 +129,8 @@
 	DATA_ERROR
 	// 404
 	NOT_FOUND
+	// json Marshal Error
+	JSON_MARSHAL_ERROR
 )
 
 type ApiManager struct {
@@ -152,7 +156,12 @@
 func (a *ApiManager) handleEndpoint(endpoint string, w http.ResponseWriter, r *http.Request) {
 	ids, org, err := extractIdentifiers(r.URL.Query())
 	if err != nil {
-		common.WriteError(w, err.Error(), INVALID_PARAMETERS, http.StatusBadRequest)
+		writeJson(http.StatusBadRequest,
+			common.ErrorResponse{
+				ResponseCode:    strconv.Itoa(INVALID_PARAMETERS),
+				ResponseMessage: err.Error(),
+				StatusCode:      http.StatusBadRequest,
+			}, w, r)
 	}
 	var res interface{}
 	var errRes *common.ErrorResponse
@@ -172,11 +181,10 @@
 	}
 
 	if errRes != nil {
-		w.WriteHeader(errRes.StatusCode)
-		writeJson(errRes, w, r)
+		writeJson(errRes.StatusCode, errRes, w, r)
 		return
 	}
-	writeJson(res, w, r)
+	writeJson(http.StatusOK, res, w, r)
 }
 
 func (a *ApiManager) HandleApps(w http.ResponseWriter, r *http.Request) {
@@ -709,13 +717,29 @@
 	}
 }
 
-func writeJson(obj interface{}, w http.ResponseWriter, r *http.Request) {
+func writeJson(code int, obj interface{}, w http.ResponseWriter, r *http.Request) {
+
+	requestId := r.Header.Get(headerRequestId)
 	bytes, err := json.Marshal(obj)
+	// JSON error
 	if err != nil {
-		log.Error("unable to marshal errorResponse: " + err.Error())
-		w.Write([]byte("unable to marshal errorResponse: " + err.Error()))
-	} else {
-		w.Header().Set("Content-Type", "application/json")
-		w.Write(bytes)
+		code = http.StatusInternalServerError
+		log.Errorf("unable to marshal errorResponse for request_id=[%s]: %v", requestId, err)
+		jsonError := &common.ErrorResponse{
+			ResponseCode:    strconv.Itoa(JSON_MARSHAL_ERROR),
+			ResponseMessage: fmt.Sprintf("JSON Marshal Error %v for object: %v", err, obj),
+			StatusCode:      http.StatusInternalServerError,
+		}
+		if bytes, err = json.Marshal(jsonError); err != nil { // this should never happen
+			log.Errorf("unable to marshal JSON error response for request_id=[%s]: %v", requestId, err)
+			w.WriteHeader(http.StatusInternalServerError)
+			return
+		}
+	}
+	w.Header().Set("Content-Type", "application/json")
+	w.WriteHeader(code)
+	log.Debugf("Sending response_code=%d for request_id=[%s]: %s", code, requestId, bytes)
+	if l, err := w.Write(bytes); err != nil || l != len(bytes) {
+		log.Errorf("error writing response for request_id=[%s]: error=%v, bytes_written=%d", requestId, err, l)
 	}
 }
diff --git a/accessEntity/api_test.go b/accessEntity/api_test.go
index eeda673..128d855 100644
--- a/accessEntity/api_test.go
+++ b/accessEntity/api_test.go
@@ -43,6 +43,7 @@
 		uri.RawQuery = query.Encode()
 		httpReq, err := http.NewRequest("GET", uri.String(), nil)
 		Expect(err).Should(Succeed())
+		httpReq.Header.Set(headerRequestId, strconv.Itoa(testCount))
 		res, err := client.Do(httpReq)
 		Expect(err).Should(Succeed())
 		defer res.Body.Close()
diff --git a/common/api.go b/common/api.go
deleted file mode 100644
index 9b3f243..0000000
--- a/common/api.go
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2017 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package common
-
-import (
-	"encoding/json"
-	"net/http"
-	"strconv"
-)
-
-func WriteError(w http.ResponseWriter, reason string, errorCode int, statusCode int) {
-	w.WriteHeader(statusCode)
-	resp := ErrorResponse{
-		ResponseCode:    strconv.Itoa(errorCode),
-		ResponseMessage: reason,
-		StatusCode:      statusCode,
-	}
-	bytes, err := json.Marshal(resp)
-	if err != nil {
-		w.Write([]byte("unable to marshal errorResponse: " + err.Error()))
-	} else {
-		w.Write(bytes)
-	}
-}