Skip to content

Commit e8866bd

Browse files
committed
refactor: fallback between sentry and telemere
style: rm secrets squash: rm commit with secrets
1 parent 543dd70 commit e8866bd

File tree

14 files changed

+166
-124
lines changed

14 files changed

+166
-124
lines changed

docker/docker-compose.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,16 @@ services:
55
- "6379:6379"
66
volumes:
77
- ./redis:/redis
8+
9+
# https://docs.localstack.cloud/user-guide/aws/s3/#s3-docker-image
10+
localstack:
11+
image: localstack/localstack:s3-latest
12+
ports:
13+
- "127.0.0.1:4566:4566" # Gateway
14+
environment:
15+
- AWS_ACCESS_KEY_ID="foo"
16+
- AWS_SECRET_ACCESS_KEY="bar"
17+
- AWS_DEFAULT_REGION=us-east-1
18+
- DEBUG=${DEBUG:-1}
19+
volumes:
20+
- "${LOCALSTACK_DIR:-./localstack}:/var/lib/localstack"

resources/config.example.edn

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
:default :dev
44
:prod :prod}
55
:release "1.0.0"
6+
:logger {:min-level :info}
67
:moclojer {:config-path #profile {:default "resources/moclojer.yml"
78
:prod "moclojer.yml"}
89
:join? #profile {:default false
@@ -25,7 +26,8 @@
2526
:opensearch {:username #or [#env OPENSEARCH_USERNAME "foobar"]
2627
:password #or [#env OPENSEARCH_PASSWORD "foobar"]
2728
:host #or [#env OPENSEARCH_HOST "foobar.com"]
28-
:port #or [#env OPENSEARCH_PORT 00000]}
29+
:port #or [#env OPENSEARCH_PORT 00000]
30+
:index "my-logs"}
2931
:mq {:uri #or [#env MQ_URL "redis://localhost:6379"]}
3032
:database {:dbtype "postgres"
3133
:jdbc-url #or [#env DATABASE_URL "postgresql://localhost:5432/postgres?user=postgres&password=postgres"]}}

src/com/moclojer/components/core.clj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
([filepath input-map]
1818
(config/map->Config {:config (config/read-config filepath input-map)})))
1919

20-
(def setup-logger logs/setup)
20+
(defn new-logger
21+
[]
22+
(logs/map->Logger {}))
2123

2224
(defn new-database []
2325
(database/map->Database {}))

src/com/moclojer/components/database.clj

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@
1313
"Builds a simple logger for debugging purposes."
1414
[ctx]
1515
(fn [operation query]
16-
(logs/log :info operation
17-
:ctx (assoc ctx :query query))))
16+
(logs/log :info operation (assoc ctx :query query))))
1817

1918
(defprotocol DatabaseProvider
2019
(execute [self command ctx]
@@ -24,7 +23,7 @@
2423
component/Lifecycle
2524
(start [this]
2625
(let [{:keys [jdbc-url]} (get-in config [:config :database])]
27-
(logs/log :info "starting database")
26+
(logs/log :info "starting database" (select-keys config [:env]))
2827
(if datasource
2928
this
3029
(assoc this :datasource (connection/->pool HikariDataSource {:jdbcUrl (to-jdbc-uri jdbc-url)})))))

src/com/moclojer/components/http.clj

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,15 @@
3838
(request
3939
[_ {:keys [method url] :as request-input} ctx]
4040
(logs/log :info "sending http request"
41-
:ctx (merge ctx {:method method
42-
:url url}))
41+
(merge ctx {:method method
42+
:url url}))
4343
(let [start-time (System/currentTimeMillis)
4444
{:keys [status] :as response} (request-fn request-input)
4545
end-time (System/currentTimeMillis)
4646
total-time (- end-time start-time)]
4747
(logs/log :info "received http response"
48-
:ctx (merge ctx {:response-time-millis total-time
49-
:status status}))
48+
(merge ctx {:response-time-millis total-time
49+
:status status}))
5050
response))
5151
(request-or-throw
5252
[this req expected-status ctx]
@@ -55,9 +55,9 @@
5555
resp
5656
(do
5757
(logs/log :error "failed critical request. throwing..."
58-
:ctx (merge ctx {:url (:url req)
59-
:status status
60-
:expected-status expected-status}))
58+
(merge ctx {:url (:url req)
59+
:status status
60+
:expected-status expected-status}))
6161
(throw (ex-info "failed critical request"
6262
(merge ctx {:status status
6363
:expected-status expected-status
@@ -90,9 +90,7 @@
9090
first :response
9191
(or {:status 500
9292
:body "mocked response not set"}))]
93-
(logs/log :info "sending http request"
94-
:ctx (merge ctx mreq))
95-
93+
(logs/log :info "sending http request" (merge ctx mreq))
9694
(assoc
9795
(if (fn? resp) (resp req) resp)
9896
:instant (System/currentTimeMillis))))
@@ -103,9 +101,9 @@
103101
resp
104102
(do
105103
(logs/log :error "failed critical request. throwing..."
106-
:ctx (merge ctx {:url (:url req)
107-
:status status
108-
:expected-status expected-status}))
104+
(merge ctx {:url (:url req)
105+
:status status
106+
:expected-status expected-status}))
109107
(throw (ex-info "failed critical request"
110108
(merge ctx {:status status
111109
:expected-status expected-status
Lines changed: 80 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,27 @@
11
(ns com.moclojer.components.logs
22
(:require
3+
[com.moclojer.components.logs :as logs]
4+
[com.stuartsierra.component :as component]
35
[clojure.core.async :as async]
46
[clojure.data.json :as json]
57
[clj-http.client :as http-client]
6-
[com.moclojer.components.sentry :as sentry]
78
[taoensso.telemere :as t])
8-
(:import [clojure.core.async.impl.channels ManyToManyChannel]))
9-
10-
(defn send-sentry-evt-from-req! [req ex]
11-
(if-let [sentry-cmp (get-in req [:components :sentry])]
12-
(sentry/send-event! sentry-cmp {:throwable ex})
13-
(prn :error "failed to send sentry event (nil component)")))
9+
(:import
10+
[clojure.core.async.impl.channels ManyToManyChannel]))
11+
12+
(let [log! (t/handler:console nil)]
13+
(defn log-console!
14+
"Uses telemere's console logger explicitly
15+
so other added handlers don't trigger."
16+
([level msg]
17+
(log-console! level msg nil nil))
18+
([level msg data]
19+
(log-console! level msg data nil))
20+
([level msg data error]
21+
(log! {:level level
22+
:data data
23+
:error error
24+
:msg_ msg}))))
1425

1526
(defn ->str-values
1627
"Adapts all values (including nested maps' values) from given
@@ -20,28 +31,30 @@
2031
[m]
2132
(reduce-kv
2233
(fn [acc k v]
23-
(assoc acc k (cond
24-
(map? v) (->str-values v)
25-
(string? v) (identity v)
26-
:else (pr-str v))))
34+
(assoc acc k (cond-> v
35+
(map? v) ->str-values
36+
(string? v) identity
37+
(boolean? v) identity
38+
:else str)))
2739
{} m))
2840

2941
(defn signal->opensearch-log
3042
"Adapts a telemere signal to a pre-defined schema for OpenSearch."
3143
[{:keys [thread location] :as signal}]
32-
(-> (select-keys signal [:level :ctx :data :msg_ :error :uid :inst])
44+
(-> (select-keys signal [:level :ctx :data :msg_ :uid :inst])
3345
(merge {"thread/group" (:group thread)
3446
"thread/name" (:name thread)
3547
"thread/id" (:id thread)
3648
"location" (str (:ns location) ":"
3749
(:line location) "x"
3850
(:column location))})
3951
(->str-values)
52+
(assoc :error (:error signal))
4053
(json/write-str)))
4154

4255
(defn build-opensearch-base-req
43-
[config index]
44-
(let [{:keys [username password host port]} config
56+
[config]
57+
(let [{:keys [username password host port index]} config
4558
url (str "https://" host ":" port "/_bulk")]
4659
{:method :post
4760
:url url
@@ -55,59 +68,72 @@
5568
(http-client/request
5669
(update base-req :body str \newline log \newline))
5770
(catch Exception e
58-
(send-sentry-evt-from-req! base-req e))))
59-
60-
(defonce log-ch (atom nil))
61-
62-
(defn setup
63-
"If on dev `env`, does basically nothing besides setting the min
64-
level. On `prod` env however, an async channel waits for log events,
65-
which are then sent to OpenSearch."
66-
[config level env & [index]]
67-
(let [prod? (= env :prod)]
68-
69-
(when-let [ch @log-ch]
70-
(async/close! ch))
71-
(reset! log-ch (async/chan))
72-
73-
(t/set-min-level! level)
74-
75-
(when (and prod? (instance? ManyToManyChannel @log-ch))
76-
(let [os-cfg (when prod? (:opensearch config))
77-
os-base-req (build-opensearch-base-req os-cfg index)]
78-
71+
(log-console! :error "failed to send opensearch log"
72+
{:log log} e))))
73+
74+
;; If on dev `env`, does basically nothing besides setting the min
75+
;; level. On `prod` env however, an async channel waits for log events,
76+
;; which are then sent to OpenSearch.
77+
(defrecord Logger [config]
78+
component/Lifecycle
79+
(start [this]
80+
(let [prod? (= (:env config) :prod)
81+
os-cfg (:opensearch config)
82+
log-ch (async/chan)
83+
os-base-req (build-opensearch-base-req os-cfg)]
84+
85+
(t/set-min-level!
86+
(or (get-in config [:logger :min-level]) :info))
87+
88+
(when (and prod? (instance? ManyToManyChannel log-ch))
7989
(t/set-ns-filter! {:disallow #{"*jetty*" "*hikari*"
8090
"*pedestal*" "*migratus*"}})
8191

8292
(t/add-handler!
83-
:opensearch
93+
::opensearch
8494
(fn [signal]
8595
(async/go
86-
(async/>! @log-ch (signal->opensearch-log signal)))))
96+
(async/>! log-ch (signal->opensearch-log signal)))))
8797

8898
(async/go
8999
(while true
90-
(let [[log _] (async/alts! [@log-ch])]
91-
(send-opensearch-log-req os-base-req log))))))))
92-
93-
(defn log [level msg & [data]]
94-
(t/log! {:level level
95-
:data data}
96-
(str msg)))
100+
(let [[log _] (async/alts! [log-ch])]
101+
(send-opensearch-log-req os-base-req log)))))
102+
103+
(assoc this :log-ch log-ch)))
104+
(stop [this]
105+
(t/remove-handler! ::opensearch)
106+
(update this :log-ch #(when % (async/close! %)))))
107+
108+
(defn log
109+
([level msg]
110+
(log level msg nil nil nil))
111+
([level msg data]
112+
(log level msg data nil nil))
113+
([level msg data ctx]
114+
(log level msg data ctx nil))
115+
([level msg data ctx error]
116+
(t/log! {:level level
117+
:ctx ctx
118+
:data data
119+
:error error}
120+
(str msg))))
97121

98122
(defn gen-ctx-with-cid []
99123
{:cid (str "cid-" (random-uuid) "-" (System/currentTimeMillis))})
100124

101125
(comment
102-
@log-ch
103-
104-
(setup {:opensearch
105-
{:username "foobar"
106-
:password "foobar"
107-
:host "foobar"
108-
:port 25060}}
109-
:info :prod "moclojer-api-logs")
110-
111-
(log :error "something happened" {:user "j0suetm"})
126+
(component/start
127+
(map->Logger
128+
{:config
129+
{:env :prod
130+
:opensearch
131+
{:username "foobar"
132+
:password "foobar"
133+
:host "foobar"
134+
:port 25060
135+
:index "components-test-logs"}}}))
136+
137+
(log :error "something happened" {:hello true})
112138
;;
113139
)

src/com/moclojer/components/moclojer.clj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616
component/Lifecycle
1717
(start [this]
1818
(let [{:keys [config-path join?]} (-> config :config :moclojer)]
19-
(logs/log :info :moclojer-start
20-
:info-server {:config-path config-path
21-
:join? join?})
19+
(logs/log :info "starting moclojer server"
20+
{:server {:config-path config-path
21+
:join? join?}})
2222
(on-startup-fn storage config-path)
2323
(assoc this :moclojer
2424
(moclojer-server!

src/com/moclojer/components/mq.clj

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,11 @@
4040
(try
4141
(handler-fn message components)
4242
(catch Throwable ex
43-
(logs/log :error "failed to handle worker"
44-
:ctx {:worker worker
45-
:message message
46-
:ex-message (.getMessage ex)})
43+
(logs/log
44+
:error "worker failed to handle message"
45+
{:worker worker
46+
:message message}
47+
nil ex)
4748
(sentry/send-event! sentry {:throwable ex})))))))
4849

4950
(defrecord MQ [config database storage http sentry workers jobs blocking?]
@@ -79,25 +80,24 @@
7980
(apply op-fn op-args))
8081
(catch Throwable ex
8182
(logs/log :error "failed to exec mq operation"
82-
:ctx (merge ctx {:op-name op-name
83-
:args args
84-
:ex-message (.getMessage ex)}))
83+
(merge ctx {:op-name op-name
84+
:args args})
85+
nil ex)
8586
(sentry/send-event! (get-in this [:components :sentry])
8687
{:throwable ex}))))
8788
(start-job! [this job]
8889
(let [{:keys [channel event sleep max-attempts]
8990
:or {sleep 2000
9091
;; max-attempts of `0` means infinite attempts.
9192
max-attempts 0}} job]
92-
(logs/log :info "starting job" :ctx {:job job})
93+
(logs/log :info "starting job" {:job job})
9394
(future
9495
(loop [attempt 1]
9596
(let [infinite-attempts? (<= max-attempts 0)
9697
attempt? (<= attempt max-attempts)]
9798
(when (or infinite-attempts? attempt?)
98-
(logs/log :info "running job"
99-
:ctx {:job job
100-
:attempt attempt})
99+
(logs/log :info "running job" {:job job
100+
:attempt attempt})
101101
(try-op! this :publish! [channel event] {})
102102
(Thread/sleep sleep)
103103
(recur (inc attempt)))))))))

0 commit comments

Comments
 (0)