Skip to content

Commit 0011a12

Browse files
committed
Support opentelemetry
1 parent 277e791 commit 0011a12

File tree

20 files changed

+313
-252
lines changed

20 files changed

+313
-252
lines changed

.cljfmt.edn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{:extra-indents {task [[:inner 0]]}}

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
## Unreleased
44

5+
- Add support for Opentelemetry via `otlp` config.
6+
- Export metrics of server tasks, tool calls, prompts, resources.
7+
58
## 0.54.4
69

710
- Use jsonrpc4clj instead of lsp4clj.

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ src="https://img.shields.io/github/stars/editor-code-assistant/eca?style=flat-sq
3333
- :coffee: **Agentic**: let LLM work as an agent with its native tools and MCPs you can configure.
3434
- :syringe: **Context**: support: giving more details about your code to the LLM, including MCP resources and prompts.
3535
- :rocket: **Multi models**: Login to OpenAI, Anthropic, Copilot, Ollama local models and many more.
36+
- :chart_with_upwards_trend: **OpenTelemetry**: Export metrics of tools, prompts, server usage.
3637

3738
## Rationale
3839

deps.edn

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
hato/hato {:mvn/version "1.0.0"}
1212
ring/ring-codec {:mvn/version "1.3.0"}
1313
ring/ring-jetty-adapter {:mvn/version "1.15.2"}
14+
com.github.steffan-westcott/clj-otel-api {:mvn/version "0.2.9"}
15+
com.github.steffan-westcott/clj-otel-sdk-extension-autoconfigure {:mvn/version "0.2.9"}
16+
com.github.steffan-westcott/clj-otel-exporter-otlp {:mvn/version "0.2.9"}
1417
camel-snake-kebab/camel-snake-kebab {:mvn/version "0.4.3"}
1518
org.slf4j/slf4j-simple {:mvn/version "2.0.17"}
1619
com.googlecode.java-diff-utils/diffutils {:mvn/version "1.3.0"}

docs/configuration.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,20 @@ ECA allows to totally customize the prompt sent to LLM via the `behavior` config
353353
}
354354
```
355355

356+
## Opentelemetry integration
357+
358+
To configure, add your OTLP collector config via `:otlp` map following [otlp auto-configure settings](https://opentelemetry.io/docs/languages/java/configuration/#properties-general). Example:
359+
360+
```javascript
361+
{
362+
"otlp": {
363+
"otel.exporter.otlp.metrics.protocol": "http/protobuf",
364+
"otel.exporter.otlp.metrics.endpoint": "https://my-otlp-endpoint.com/foo",
365+
"otel.exporter.otlp.headers": "Authorization=Bearer 123456"
366+
}
367+
}
368+
```
369+
356370
## All configs
357371

358372
=== "Schema"
@@ -429,6 +443,7 @@ ECA allows to totally customize the prompt sent to LLM via the `behavior` config
429443
maxEntriesPerDir?: number;
430444
};
431445
};
446+
otlp?: {[key: string]: string};
432447
}
433448
```
434449

docs/features.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ Current supported providers with login:
111111
- `anthropic`: with options to login to Claude Max/Pro or create API keys.
112112
- `github-copilot`: via Github oauth.
113113

114+
## OpenTelemetry integration
115+
116+
ECA has support for [OpenTelemetry](https://opentelemetry.io/)(otlp), if configured, server tasks, tool calls, and more will be metrified via otlp API.
117+
118+
For more details check [its configuration](./configuration.md#opentelemetry-integration)
119+
114120
## Completion
115121

116122
Soon

resources/META-INF/native-image/eca/eca/native-image.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ Args=-J-Dborkdude.dynaload.aot=true \
55
--enable-url-protocols=jar,http,https \
66
--initialize-at-build-time=com.fasterxml.jackson \
77
--initialize-at-build-time=org.yaml.snakeyaml \
8+
--initialize-at-build-time=io.opentelemetry.api.common.AttributeType \
9+
--initialize-at-build-time=io.opentelemetry.api.logs.Severity \
810
-H:-CheckToolchain \
911
-H:Log=registerResource: \
1012
-H:IncludeResources=ECA_VERSION \

src/eca/config.clj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,8 @@
249249
[:behavior :ANY :toolCall :approval :ask]
250250
[:behavior :ANY :toolCall :approval :ask :ANY :argsMatchers]
251251
[:behavior :ANY :toolCall :approval :deny]
252-
[:behavior :ANY :toolCall :approval :deny :ANY :argsMatchers]]})
252+
[:behavior :ANY :toolCall :approval :deny :ANY :argsMatchers]
253+
[:otlp]]})
253254

254255
(defn all [db]
255256
(let [initialization-config @initialization-config*

src/eca/db.clj

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,9 @@
7575
(defn ^:private transit-global-db-file []
7676
(io/file (global-cache-dir) "db.transit.json"))
7777

78-
(defn ^:private read-cache [cache-file]
78+
(defn ^:private read-cache [cache-file metrics]
7979
(try
80-
(metrics/task
81-
:db/read-cache
80+
(metrics/task metrics :db/read-cache
8281
(if (fs/exists? cache-file)
8382
(let [cache (with-open [is (io/input-stream cache-file)]
8483
(transit/read (transit/reader is :json)))]
@@ -88,10 +87,9 @@
8887
(catch Throwable e
8988
(logger/error logger-tag "Could not load global cache from DB" e))))
9089

91-
(defn ^:private upsert-cache! [cache cache-file]
90+
(defn ^:private upsert-cache! [cache cache-file metrics]
9291
(try
93-
(metrics/task
94-
:db/upsert-cache
92+
(metrics/task metrics :db/upsert-cache
9593
(io/make-parents cache-file)
9694
;; https://github.com/cognitect/transit-clj/issues/43
9795
(with-open [os ^OutputStream (no-flush-output-stream (io/output-stream cache-file))]
@@ -100,22 +98,22 @@
10098
(catch Throwable e
10199
(logger/error logger-tag (str "Could not upsert db cache to " cache-file) e))))
102100

103-
(defn ^:private read-global-cache []
104-
(let [cache (read-cache (transit-global-db-file))]
101+
(defn ^:private read-global-cache [metrics]
102+
(let [cache (read-cache (transit-global-db-file) metrics)]
105103
(when (= version (:version cache))
106104
cache)))
107105

108-
(defn ^:private read-global-by-workspaces-cache [workspaces]
109-
(let [cache (read-cache (transit-global-by-workspaces-db-file workspaces))]
106+
(defn ^:private read-global-by-workspaces-cache [workspaces metrics]
107+
(let [cache (read-cache (transit-global-by-workspaces-db-file workspaces) metrics)]
110108
(when (= version (:version cache))
111109
cache)))
112110

113-
(defn load-db-from-cache! [db* config]
111+
(defn load-db-from-cache! [db* config metrics]
114112
(when-not (:pureConfig config)
115-
(when-let [global-cache (read-global-cache)]
113+
(when-let [global-cache (read-global-cache metrics)]
116114
(logger/info logger-tag "Loading from global-cache caches...")
117115
(swap! db* shared/deep-merge global-cache))
118-
(when-let [global-by-workspace-cache (read-global-by-workspaces-cache (:workspace-folders @db*))]
116+
(when-let [global-by-workspace-cache (read-global-by-workspaces-cache (:workspace-folders @db*) metrics)]
119117
(logger/info logger-tag "Loading from workspace-cache caches...")
120118
(swap! db* shared/deep-merge global-by-workspace-cache))))
121119

@@ -130,12 +128,12 @@
130128
(defn ^:private normalize-db-for-global-write [db]
131129
(select-keys db [:auth]))
132130

133-
(defn update-workspaces-cache! [db]
131+
(defn update-workspaces-cache! [db metrics]
134132
(-> (normalize-db-for-workspace-write db)
135133
(assoc :version version)
136-
(upsert-cache! (transit-global-by-workspaces-db-file (:workspace-folders db)))))
134+
(upsert-cache! (transit-global-by-workspaces-db-file (:workspace-folders db)) metrics)))
137135

138-
(defn update-global-cache! [db]
136+
(defn update-global-cache! [db metrics]
139137
(-> (normalize-db-for-global-write db)
140138
(assoc :version version)
141-
(upsert-cache! (transit-global-db-file))))
139+
(upsert-cache! (transit-global-db-file) metrics)))

src/eca/features/chat.clj

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,14 @@
3232
:role role
3333
:content content}))
3434

35-
(defn finish-chat-prompt! [status {:keys [chat-id db* on-finished-side-effect] :as chat-ctx}]
35+
(defn finish-chat-prompt! [status {:keys [chat-id db* metrics on-finished-side-effect] :as chat-ctx}]
3636
(swap! db* assoc-in [:chats chat-id :status] status)
3737
(send-content! chat-ctx :system
3838
{:type :progress
3939
:state :finished})
4040
(when on-finished-side-effect
4141
(on-finished-side-effect))
42-
(db/update-workspaces-cache! @db*))
42+
(db/update-workspaces-cache! @db* metrics))
4343

4444
(defn ^:private assert-chat-not-stopped! [{:keys [chat-id db*] :as chat-ctx}]
4545
(when (identical? :stopping (get-in @db* [:chats chat-id :status]))
@@ -367,7 +367,7 @@
367367

368368
(defn ^:private prompt-messages!
369369
[user-messages
370-
{:keys [db* config chat-id behavior full-model instructions messenger] :as chat-ctx}]
370+
{:keys [db* config chat-id behavior full-model instructions messenger metrics] :as chat-ctx}]
371371
(let [db @db*
372372
[provider model] (string/split full-model #"/" 2)
373373
past-messages (get-in db [:chats chat-id :messages] [])
@@ -490,7 +490,7 @@
490490
(delay
491491
(future
492492
;; assert: In :executing
493-
(let [result (f.tools/call-tool! name arguments db* config messenger behavior chat-id)
493+
(let [result (f.tools/call-tool! name arguments behavior chat-id db* config messenger metrics)
494494
details (f.tools/tool-call-details-after-invocation name arguments details result)
495495
{:keys [start-time]} (get-tool-call-state @db* chat-id id)]
496496
(add-to-history! {:role "tool_call"
@@ -631,7 +631,8 @@
631631
[{:keys [message model behavior contexts chat-id]}
632632
db*
633633
messenger
634-
config]
634+
config
635+
metrics]
635636
(let [message (string/trim message)
636637
chat-id (or chat-id
637638
(let [new-id (str (random-uuid))]
@@ -666,6 +667,7 @@
666667
:instructions instructions
667668
:full-model full-model
668669
:db* db*
670+
:metrics metrics
669671
:config config
670672
:messenger messenger}
671673
decision (message->decision message)
@@ -743,6 +745,6 @@
743745
(finish-chat-prompt! :stopping chat-ctx))))
744746

745747
(defn delete-chat
746-
[{:keys [chat-id]} db*]
748+
[{:keys [chat-id]} db* metrics]
747749
(swap! db* update :chats dissoc chat-id)
748-
(db/update-workspaces-cache! @db*))
750+
(db/update-workspaces-cache! @db* metrics))

0 commit comments

Comments
 (0)