aboutsummaryrefslogtreecommitdiffstats
path: root/src/chameleon/logging.clj
diff options
context:
space:
mode:
Diffstat (limited to 'src/chameleon/logging.clj')
-rw-r--r--src/chameleon/logging.clj123
1 files changed, 123 insertions, 0 deletions
diff --git a/src/chameleon/logging.clj b/src/chameleon/logging.clj
new file mode 100644
index 0000000..15e1e7b
--- /dev/null
+++ b/src/chameleon/logging.clj
@@ -0,0 +1,123 @@
+(ns chameleon.logging
+ (:require [camel-snake-kebab.core :as cs]
+ [camel-snake-kebab.extras :refer [transform-keys]]
+ [clojure.java.io :as io]
+ [integrant.core :as ig]
+ [clojure.spec.alpha :as s])
+ (:import [org.onap.aai.cl.api Logger LogFields LogLine]
+ [org.onap.aai.cl.eelf LoggerFactory LogMessageEnum AaiLoggerAdapter AuditLogLine]
+ [org.onap.aai.cl.mdc MdcContext MdcOverride]
+ [com.att.eelf.i18n EELFResourceManager]
+ [clojure.lang.IFn]
+ [org.slf4j MDC]))
+
+(declare LOGLINE_DEFINED_FIELDS error-logger audit-logger ->java string->enum logfields)
+
+(defmethod ig/init-key :chameleon/loggers
+ [_ {:keys [logback logmsgs] :or {logback (.getPath (io/file "chameleon_logback.xml"))
+ logmsgs "log/ChameleonMsgs"}}]
+ (System/setProperty "logback.configurationFile" logback)
+ (EELFResourceManager/loadMessageBundle logmsgs)
+ [(error-logger "chameleon.loggging") (audit-logger "chameleon.loggging")])
+
+(defn conform-multiple
+ [& spec-form-pair]
+ (if (s/valid? :chameleon.specs/spec-form-pair spec-form-pair)
+ (->> spec-form-pair
+ (partition 2)
+ (map (fn [[sp form]]
+ (when (s/invalid? (s/conform sp form))
+ (s/explain-data sp form))))
+ (remove nil?))
+ (s/explain-data :chameleon.specs/spec-form-pair spec-form-pair)))
+
+(defn mdc-set!
+ "Sets the global MDC context for the current thread."
+ [m]
+ (doseq [[k v] m] (MDC/put k v)))
+
+(defn mdc-init!
+ "Sets the global MDC context as required by the EELF logging library"
+ [transaction-id service instance partner client-address]
+ (MdcContext/initialize transaction-id service instance partner client-address))
+
+(defn mdc-clear! [] (MDC/clear))
+
+(defmacro with-mdc
+ "Will set the global MDC context with the options (will convert from
+ keywords to PascalCase), execute the log, and clear the MDC
+ context."
+ [opts & body]
+ `(do
+ (mdc-set! (transform-keys cs/->PascalCaseString ~opts))
+ ~@body
+ (mdc-clear)))
+
+(defn mdc-override
+ [m]
+ (->java (fn [j k v] (.addAttribute j k v)) (new MdcOverride)
+ (transform-keys cs/->PascalCaseString m)))
+
+(defn error-logger
+ [name]
+ (.getLogger (LoggerFactory/getInstance) name))
+
+(defn audit-logger
+ [name]
+ (.getAuditLogger (LoggerFactory/getInstance) name))
+
+(defn logger?
+ [logger]
+ (instance? AaiLoggerAdapter logger))
+
+(defn info
+ [^AaiLoggerAdapter logger ^String enum msgs & {:keys [fields] :or {fields {}}}]
+ (let [confirmed-specs (conform-multiple :logging/valid-fields fields :logging/msgs msgs
+ :chameleon.specs/logger logger)]
+ (if (empty? confirmed-specs)
+ (.info logger (string->enum enum) (logfields fields) (into-array java.lang.String msgs))
+ confirmed-specs)))
+
+(defn debug
+ [^AaiLoggerAdapter logger ^String enum msgs]
+ (.debug logger (string->enum enum) (into-array java.lang.String msgs)))
+
+(defn valid-logfields?
+ [m]
+ (->> (keys m)
+ (map cs/->SCREAMING_SNAKE_CASE_STRING)
+ set
+ (clojure.set/superset? (-> LOGLINE_DEFINED_FIELDS keys set))))
+
+(def ^{:private true
+ :doc "Adding these fields from \"org.onap.aai.cl.api.LogLine\"
+ class. Right now there isn't a known way to use the ENUMs of an
+ abstract JAVA class if they are not STATIC. The field order is very
+ specific and it should be maintained for the common logging library
+ version \"1.2.2\". For a better understanding, please look at the
+ \"DefinedFields\" ENUMs in the org.onap.aai.cl.api.LogLine
+ class"}
+
+ LOGLINE_DEFINED_FIELDS
+ (zipmap ["STATUS_CODE" "RESPONSE_CODE" "RESPONSE_DESCRIPTION" "INSTANCE_UUID"
+ "SEVERITY" "SERVER_IP" "CLIENT_IP" "CLASS_NAME" "PROCESS_KEY"
+ "TARGET_SVC_NAME" "TARGET_ENTITY" "ERROR_CODE" "ERROR_DESCRIPTION"
+ "CUSTOM_1" "CUSTOM_2""CUSTOM_3" "CUSTOM_4"]
+ (range)))
+
+(defn- string->enum
+ ([^String enum] (proxy [Enum LogMessageEnum] [enum (hash enum)]))
+ ([^String enum ordinal] (proxy [Enum LogMessageEnum] [enum ordinal])))
+
+(defn- ->java
+ [f jc m]
+ (reduce (fn [a [k v]] (f a k v) a)
+ jc m))
+
+(defn- logfields
+ "Generate a \"LogFields\" object with all the fields set."
+ [m]
+ (->> m
+ (transform-keys cs/->SCREAMING_SNAKE_CASE_STRING)
+ (transform-keys #(string->enum % (LOGLINE_DEFINED_FIELDS %)))
+ (->java (fn [j field v] (.setField j field v)) (new LogFields))))