From 96bf8074d724e2e2b677fae7f004b6e43a16ff03 Mon Sep 17 00:00:00 2001 From: Trent Mick Date: Mon, 6 Jan 2025 14:59:33 -0800 Subject: [PATCH 1/6] chore(instr-openai): use more common .example suffix, rather than .template (#511) --- packages/instrumentation-openai/TESTING.md | 6 +++--- .../{azure.env.template => azure.env.example} | 0 .../{openai.env.template => openai.env.example} | 0 packages/instrumentation-openai/test/fixtures.test.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename packages/instrumentation-openai/{azure.env.template => azure.env.example} (100%) rename packages/instrumentation-openai/{openai.env.template => openai.env.example} (100%) diff --git a/packages/instrumentation-openai/TESTING.md b/packages/instrumentation-openai/TESTING.md index 162d5ecb..89bf1cdb 100644 --- a/packages/instrumentation-openai/TESTING.md +++ b/packages/instrumentation-openai/TESTING.md @@ -32,7 +32,7 @@ or a running Ollama. Which is used is determined by the environment variables. 1. OpenAI ```bash - cp openai.env.template openai.env + cp openai.env.example openai.env vi openai.env # Add your OpenAI credentials. set -a; source ./openai.env @@ -42,7 +42,7 @@ or a running Ollama. Which is used is determined by the environment variables. 2. Azure OpenAI ```bash - cp azure.env.template azure.env + cp azure.env.example azure.env vi azure.env # Add your credentials and resource & deployment details. set -a; source ./azure.env @@ -96,7 +96,7 @@ ones, those recordings might need to be regenerated. This runs against api.openai.com, so you must have valid OpenAI auth set in your environment. ```bash -cp openai.env.template openai.env +cp openai.env.example openai.env vi openai.env # Add your OpenAI credentials. set -a; source openai.env diff --git a/packages/instrumentation-openai/azure.env.template b/packages/instrumentation-openai/azure.env.example similarity index 100% rename from packages/instrumentation-openai/azure.env.template rename to packages/instrumentation-openai/azure.env.example diff --git a/packages/instrumentation-openai/openai.env.template b/packages/instrumentation-openai/openai.env.example similarity index 100% rename from packages/instrumentation-openai/openai.env.template rename to packages/instrumentation-openai/openai.env.example diff --git a/packages/instrumentation-openai/test/fixtures.test.js b/packages/instrumentation-openai/test/fixtures.test.js index fb0f4653..dffce81f 100644 --- a/packages/instrumentation-openai/test/fixtures.test.js +++ b/packages/instrumentation-openai/test/fixtures.test.js @@ -144,7 +144,7 @@ switch (testMode) { } if (!process.env.OPENAI_API_KEY) { throw new Error( - 'OPENAI_API_KEY is not set. To regenerate-recordings, it must be set. Set it in your environment, or use TEST_FIXTURES_ENV_FILE="./openai.env" (see "openai.env.template").' + 'OPENAI_API_KEY is not set. To regenerate-recordings, it must be set. Set it in your environment, or use TEST_FIXTURES_ENV_FILE="./openai.env" (see "openai.env.example").' ); } usingNock = true; From 441445b7d28e8eb3de178adc3340f6bd2b7a501f Mon Sep 17 00:00:00 2001 From: Trent Mick Date: Tue, 7 Jan 2025 10:38:40 -0800 Subject: [PATCH 2/6] chore: fix lint (style after a recent change) (#513) --- .../instrumentation-openai/test/fixtures/chat-completion.js | 3 +-- .../instrumentation-openai/test/fixtures/streaming-abort.js | 3 +-- .../test/fixtures/streaming-bad-iterate.js | 3 +-- .../test/fixtures/streaming-chat-completion.js | 3 +-- .../test/fixtures/streaming-with-include_usage.js | 3 +-- .../instrumentation-openai/test/fixtures/streaming-with-tee.js | 3 +-- 6 files changed, 6 insertions(+), 12 deletions(-) diff --git a/packages/instrumentation-openai/test/fixtures/chat-completion.js b/packages/instrumentation-openai/test/fixtures/chat-completion.js index d16df799..7c27ee12 100644 --- a/packages/instrumentation-openai/test/fixtures/chat-completion.js +++ b/packages/instrumentation-openai/test/fixtures/chat-completion.js @@ -24,8 +24,7 @@ async function main() { const messages = [ { role: 'user', - content: - 'Answer in up to 3 words: Which ocean contains Bouvet Island?', + content: 'Answer in up to 3 words: Which ocean contains Bouvet Island?', }, ]; const chatCompletion = await client.chat.completions.create({ diff --git a/packages/instrumentation-openai/test/fixtures/streaming-abort.js b/packages/instrumentation-openai/test/fixtures/streaming-abort.js index 3f3aab8c..b6b6fe1e 100644 --- a/packages/instrumentation-openai/test/fixtures/streaming-abort.js +++ b/packages/instrumentation-openai/test/fixtures/streaming-abort.js @@ -26,8 +26,7 @@ async function main() { messages: [ { role: 'user', - content: - 'Answer in up to 3 words: Which ocean contains Bouvet Island?', + content: 'Answer in up to 3 words: Which ocean contains Bouvet Island?', }, ], stream: true, diff --git a/packages/instrumentation-openai/test/fixtures/streaming-bad-iterate.js b/packages/instrumentation-openai/test/fixtures/streaming-bad-iterate.js index 73b7268b..c66f4333 100644 --- a/packages/instrumentation-openai/test/fixtures/streaming-bad-iterate.js +++ b/packages/instrumentation-openai/test/fixtures/streaming-bad-iterate.js @@ -26,8 +26,7 @@ async function main() { messages: [ { role: 'user', - content: - 'Answer in up to 3 words: Which ocean contains Bouvet Island?', + content: 'Answer in up to 3 words: Which ocean contains Bouvet Island?', }, ], stream: true, diff --git a/packages/instrumentation-openai/test/fixtures/streaming-chat-completion.js b/packages/instrumentation-openai/test/fixtures/streaming-chat-completion.js index 17579d24..e6822c3f 100644 --- a/packages/instrumentation-openai/test/fixtures/streaming-chat-completion.js +++ b/packages/instrumentation-openai/test/fixtures/streaming-chat-completion.js @@ -26,8 +26,7 @@ async function main() { messages: [ { role: 'user', - content: - 'Answer in up to 3 words: Which ocean contains Bouvet Island?', + content: 'Answer in up to 3 words: Which ocean contains Bouvet Island?', }, ], stream: true, diff --git a/packages/instrumentation-openai/test/fixtures/streaming-with-include_usage.js b/packages/instrumentation-openai/test/fixtures/streaming-with-include_usage.js index c770f89e..88572b99 100644 --- a/packages/instrumentation-openai/test/fixtures/streaming-with-include_usage.js +++ b/packages/instrumentation-openai/test/fixtures/streaming-with-include_usage.js @@ -26,8 +26,7 @@ async function main() { messages: [ { role: 'user', - content: - 'Answer in up to 3 words: Which ocean contains Bouvet Island?', + content: 'Answer in up to 3 words: Which ocean contains Bouvet Island?', }, ], stream: true, diff --git a/packages/instrumentation-openai/test/fixtures/streaming-with-tee.js b/packages/instrumentation-openai/test/fixtures/streaming-with-tee.js index c226e324..2c82900f 100644 --- a/packages/instrumentation-openai/test/fixtures/streaming-with-tee.js +++ b/packages/instrumentation-openai/test/fixtures/streaming-with-tee.js @@ -26,8 +26,7 @@ async function main() { messages: [ { role: 'user', - content: - 'Answer in up to 3 words: Which ocean contains Bouvet Island?', + content: 'Answer in up to 3 words: Which ocean contains Bouvet Island?', }, ], stream: true, From 267db38db6850f5ce26fbe785da19c0f267e8522 Mon Sep 17 00:00:00 2001 From: Trent Mick Date: Tue, 7 Jan 2025 10:39:50 -0800 Subject: [PATCH 3/6] chore(instr-openai): avoid '@typescript-eslint/no-explicit-any' warnings (#498) ... because GH has a 'feature' called 'annotations' to show these warnings on all PR diffs, even if that file was not part of that PR. There isn't a way to turn this misfeature off in GH, so this is the tail wagging the dog a bit. --- .../src/instrumentation.ts | 28 +++++++++++++++---- packages/instrumentation-openai/src/utils.ts | 8 ++++-- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/packages/instrumentation-openai/src/instrumentation.ts b/packages/instrumentation-openai/src/instrumentation.ts index 2d0b5bc3..4a0bd03a 100644 --- a/packages/instrumentation-openai/src/instrumentation.ts +++ b/packages/instrumentation-openai/src/instrumentation.ts @@ -66,8 +66,9 @@ import { // Use `DEBUG=elastic-opentelemetry-instrumentation-openai ...` for debug output. // Or use `node --env-file ./dev.env ...` in this repo. -import createDebug from 'debug'; -const debug = createDebug('elastic-opentelemetry-instrumentation-openai'); +import Debug from 'debug'; +const debug = Debug('elastic-opentelemetry-instrumentation-openai'); +// eslint-disable-next-line @typescript-eslint/no-explicit-any (debug as any).inspectOpts = { depth: 50, colors: true }; export class OpenAIInstrumentation extends InstrumentationBase { @@ -157,16 +158,19 @@ export class OpenAIInstrumentation extends InstrumentationBase any) => { // https://platform.openai.com/docs/api-reference/chat/create + // eslint-disable-next-line @typescript-eslint/no-explicit-any return function patchedCreate(this: any, ...args: unknown[]) { if (!self.isEnabled) { return original.apply(this, args); } debug('OpenAI.Chat.Completions.create args: %O', args); - const params = - args[0] as any; /* type ChatCompletionCreateParamsStreaming */ + /** type ChatCompletionCreateParamsStreaming */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const params = args[0] as any; const config = self.getConfig(); const startNow = performance.now(); @@ -183,6 +187,7 @@ export class OpenAIInstrumentation extends InstrumentationBase = context.with(ctx, () => original.apply(this, args) ); @@ -239,7 +244,7 @@ export class OpenAIInstrumentation extends InstrumentationBase { // `msg` is Array let body; @@ -328,6 +334,7 @@ export class OpenAIInstrumentation extends InstrumentationBase { return { id: tc.id, @@ -388,6 +395,7 @@ export class OpenAIInstrumentation extends InstrumentationBase, span: Span, startNow: number, @@ -401,6 +409,7 @@ export class OpenAIInstrumentation extends InstrumentationBase c.finish_reason) ); span.setAttribute(ATTR_GEN_AI_RESPONSE_ID, result.id); @@ -542,6 +553,7 @@ export class OpenAIInstrumentation extends InstrumentationBase { let message: Partial; if (config.captureMessageContent) { @@ -553,6 +565,7 @@ export class OpenAIInstrumentation extends InstrumentationBase { return { id: tc.id, @@ -640,8 +653,10 @@ export class OpenAIInstrumentation extends InstrumentationBase { // https://platform.openai.com/docs/api-reference/embeddings/create + // eslint-disable-next-line @typescript-eslint/no-explicit-any return function patchedCreate(this: any, ...args: unknown[]) { if (!self.isEnabled) { return original.apply(this, args); @@ -664,6 +679,7 @@ export class OpenAIInstrumentation extends InstrumentationBase original.apply(this, args)); apiPromise + // eslint-disable-next-line @typescript-eslint/no-explicit-any .then((result: any) => { self._onEmbeddingsCreateResult(span, startNow, commonAttrs, result); }) @@ -682,6 +698,7 @@ export class OpenAIInstrumentation extends InstrumentationBase Date: Tue, 7 Jan 2025 17:07:50 -0800 Subject: [PATCH 4/6] chore: "slack-lite" notifications for issue/PR open/close actions (#496) --- .github/workflows/slack.yml | 144 ++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 .github/workflows/slack.yml diff --git a/.github/workflows/slack.yml b/.github/workflows/slack.yml new file mode 100644 index 00000000..f148faf2 --- /dev/null +++ b/.github/workflows/slack.yml @@ -0,0 +1,144 @@ +# Post a slack message something like the following for issue and PR actions: +# <$url|$title> +# | $repo#$num · issue opened by $user +# +# Configuration: +# 1. Set `SLACK_CHANNEL`. +# 2. Add a `SLACK_BOT_TOKEN` secret to your repo. This is the "Bot User OAuth +# Token" from the "OAuth & Permissions" section of your Slack App +# (https://api.slack.com/apps). The token must have the `chat:write` +# permission. +# 3. Optionally tweak the `if:` and `on:` sections below to control which issue +# and PR events are skipped. + +name: slack + +env: + SLACK_CHANNEL: "#apm-agent-node" + +on: + issues: + types: [opened, reopened, closed] + pull_request: + types: [opened, ready_for_review, reopened, closed] + +jobs: + slack: + # Skip notification if: + # - dependabot PRs, too noisy + # - draft PRs + if: ${{ !(github.event.action == 'opened' && github.event.pull_request.draft) || + github.event.pull_request.user.login != 'dependabot[bot]' || + github.event.pull_request.user.login != 'elastic-renovate-prod[bot]' }} + runs-on: ubuntu-latest + steps: + - name: Prepare Slack message + id: prepare + shell: python + env: + GITHUB_CONTEXT: ${{ toJson(github) }} + run: | + import os + from pprint import pprint + import json + + CLOSED_RED = '#cb2431' + GITHUB_BLACK = '#24292f' + MERGED_PURPLE = '#6f42c1' + OPEN_GREEN = '#36a64f' + DRAFT_GRAY = '#6a737d' + + ctx = json.loads(os.environ["GITHUB_CONTEXT"]) + # pprint(ctx) # for dev/debugging + event = ctx["event"] + action = event["action"] + if "issue" in event: + title = event["issue"]["title"] + url = event["issue"]["html_url"] + num = event["issue"]["number"] + action_str = f"issue {action}" + color = { + "opened": OPEN_GREEN, + "reopened": OPEN_GREEN, + "closed": CLOSED_RED, + }.get(action, "#ffffff") + elif "pull_request" in event: + title = event["pull_request"]["title"] + url = event["pull_request"]["html_url"] + num = event["pull_request"]["number"] + if action == "closed": + if event["pull_request"]["merged"]: + action_str = "PR merged" + color = MERGED_PURPLE + else: + action_str = "PR closed" + color = CLOSED_RED + elif event["pull_request"]["draft"]: + action_str = "PR in draft" + color = DRAFT_GRAY + elif action == "ready_for_review": + action_str = "PR ready for review" + color = OPEN_GREEN + else: + action_str = "PR opened" + color = OPEN_GREEN + else: + pprint(ctx) + raise ValueError('unexpected event: not an issue or PR event') + + def gfm2slack(text): + """Limited conversion of the subset of GitHub Flavor Markdown (gfm) + supported in GitHub issue/PR titles to a safe string for a Slack + link. https://api.slack.com/reference/surfaces/formatting""" + # Escape angle brackets to allow usage in Slack link. + text = text.replace('<', '<') + text = text.replace('>', '>') + # TODO: How to escape asterisk bolding and underscore italicizing? + return text + + # Use https://app.slack.com/block-kit-builder to play with styling. + payload = { + "channel": os.environ["SLACK_CHANNEL"], + # Note: Omitting the "text" field is intentional, so that it is not + # rendered by default. Guidelines on accessibility in: + # https://api.slack.com/methods/chat.postMessage#text-blocks-attachments + # are unclear for "attachments" usage. This competes with: + # https://api.slack.com/reference/messaging/attachments#guidelines__message-attachments-as-objects + # guidelines to group all object data inside the attachment. + # The downside is that the `chatMessage` below results in warnings + # from the Slack API about not including the top-level "text". + #"text": f"<{url}|{gfm2slack(title)}>", + "attachments": [ + { + "color": color, + "blocks": [ + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": f"<{url}|{gfm2slack(title)}>" + } + }, + { + "type": "context", + "elements": [ + { + "type": "mrkdwn", + "text": f"{ctx['repository']}#{num} · *{action_str}* by {event['sender']['login']}" + } + ] + } + ] + } + ] + } + + with open(os.environ.get("GITHUB_OUTPUT"), "a") as f: + f.write("payload={}".format(json.dumps(payload))) + + - name: Post Slack message + uses: slackapi/slack-github-action@v2.0.0 + with: + method: chat.postMessage + token: ${{ secrets.SLACK_BOT_TOKEN }} + payload: ${{ steps.prepare.outputs.payload }} From 78bcc5b6e60cd2a1e0d9e7f6a5ff7c05845564f2 Mon Sep 17 00:00:00 2001 From: Trent Mick Date: Tue, 7 Jan 2025 23:26:51 -0800 Subject: [PATCH 5/6] chore: improved OpenAI + EDOT Node.js examples (#512) --- .gitignore | 1 + examples/openai/.npmrc | 1 + examples/openai/README.md | 64 ++++++++++++++++++ examples/{openai-chat.js => openai/chat.js} | 28 ++++---- examples/openai/embeddings.js | 73 +++++++++++++++++++++ examples/openai/env.example | 22 +++++++ examples/openai/package.json | 24 +++++++ 7 files changed, 202 insertions(+), 11 deletions(-) create mode 100644 examples/openai/.npmrc create mode 100644 examples/openai/README.md rename examples/{openai-chat.js => openai/chat.js} (66%) create mode 100644 examples/openai/embeddings.js create mode 100644 examples/openai/env.example create mode 100644 examples/openai/package.json diff --git a/.gitignore b/.gitignore index dae2806f..2c078379 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.env node_modules npm-debug.log* build diff --git a/examples/openai/.npmrc b/examples/openai/.npmrc new file mode 100644 index 00000000..43c97e71 --- /dev/null +++ b/examples/openai/.npmrc @@ -0,0 +1 @@ +package-lock=false diff --git a/examples/openai/README.md b/examples/openai/README.md new file mode 100644 index 00000000..9cb8717c --- /dev/null +++ b/examples/openai/README.md @@ -0,0 +1,64 @@ +# OpenAI Zero-Code Instrumentation Examples + +This is an example of how to instrument OpenAI calls with zero code changes, +using `@elastic/opentelemetry-node` included in the Elastic Distribution of +OpenTelemetry Node.js ([EDOT Node.js][edot-node]). + +When OpenAI examples run, they export traces, metrics and logs to an OTLP +compatible endpoint. Traces and metrics include details such as the model used +and the duration of the LLM request. In the case of chat, Logs capture the +request and the generated response. The combination of these provide a +comprehensive view of the performance and behavior of your OpenAI usage. + +## Install + +First, set up a Node.js environment for the examples like this: + +```bash +nvm use --lts # or similar to setup Node.js v20 or later +npm install +``` + +## Configure + +Copy [env.example](env.example) to `.env` and update its `OPENAI_API_KEY`. + +An OTLP compatible endpoint should be listening for traces, metrics and logs on +`http://localhost:4318`. If not, update `OTEL_EXPORTER_OTLP_ENDPOINT` as well. +For example, if Elastic APM server is running locally, edit `.env` like this: +``` +OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:8200 +``` + +## Run + +There are two examples, and they run the same way: + +### Chat + +[chat.js](chat.js) asks the LLM a geography question and prints the response. + +Run it like this: +```bash +node --env-file .env --require @elastic/opentelemetry-node chat.js +``` + +You should see something like "Atlantic Ocean" unless your LLM hallucinates! + +### Embeddings + + +[embeddings.js](embeddings.js) creates in-memory VectorDB embeddings about +Elastic products. Then, it searches for one similar to a question. + +Run it like this: +```bash +node --env-file .env --require @elastic/opentelemetry-node embeddings.js +``` + +You should see something like "Connectors can help you connect to a database", +unless your LLM hallucinates! + +--- + +[edot-node]: https://github.com/elastic/elastic-otel-node/blob/main/packages/opentelemetry-node/README.md#install diff --git a/examples/openai-chat.js b/examples/openai/chat.js similarity index 66% rename from examples/openai-chat.js rename to examples/openai/chat.js index 5c35287f..afd45604 100644 --- a/examples/openai-chat.js +++ b/examples/openai/chat.js @@ -17,20 +17,26 @@ * under the License. */ -// Usage: -// OPENAI_API_KEY=sk-... \ -// node -r @elastic/opentelemetry-node openai-chat.js - const {OpenAI} = require('openai'); +let chatModel = process.env.CHAT_MODEL ?? 'gpt-4o-mini'; + async function main() { - const openai = new OpenAI(); - const result = await openai.chat.completions.create({ - model: 'gpt-4o-mini', - messages: [ - {role: 'user', content: 'Why is the sky blue? Answer briefly.'}, - ], + const client = new OpenAI(); + + const messages = [ + { + role: 'user', + content: + 'Answer in up to 3 words: Which ocean contains Bouvet Island?', + }, + ]; + + const chatCompletion = await client.chat.completions.create({ + model: chatModel, + messages: messages, }); - console.log(result.choices[0]?.message?.content); + console.log(chatCompletion.choices[0].message.content); } + main(); diff --git a/examples/openai/embeddings.js b/examples/openai/embeddings.js new file mode 100644 index 00000000..bd1c01df --- /dev/null +++ b/examples/openai/embeddings.js @@ -0,0 +1,73 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you 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. + */ + +const {OpenAI} = require('openai'); +const {dot, norm} = require('mathjs'); + +let embeddingsModel = process.env.EMBEDDINGS_MODEL ?? 'text-embedding-3-small'; + +async function main() { + const client = new OpenAI(); + + const products = [ + "Search: Ingest your data, and explore Elastic's machine learning and retrieval augmented generation (RAG) capabilities.", + 'Observability: Unify your logs, metrics, traces, and profiling at scale in a single platform.', + 'Security: Protect, investigate, and respond to cyber threats with AI-driven security analytics.', + 'Elasticsearch: Distributed, RESTful search and analytics.', + 'Kibana: Visualize your data. Navigate the Stack.', + 'Beats: Collect, parse, and ship in a lightweight fashion.', + 'Connectors: Connect popular databases, file systems, collaboration tools, and more.', + 'Logstash: Ingest, transform, enrich, and output.', + ]; + + // Generate embeddings for each product. Keep them in an array instead of a vector DB. + const productEmbeddings = []; + for (const product of products) { + productEmbeddings.push(await createEmbedding(client, product)); + } + + const queryEmbedding = await createEmbedding( + client, + 'What can help me connect to a database?' + ); + + // Calculate cosine similarity between the query and document embeddings + const similarities = productEmbeddings.map((productEmbedding) => { + return ( + dot(queryEmbedding, productEmbedding) / + (norm(queryEmbedding) * norm(productEmbedding)) + ); + }); + + // Get the index of the most similar document + const mostSimilarIndex = similarities.indexOf(Math.max(...similarities)); + + console.log(products[mostSimilarIndex]); +} + +async function createEmbedding(client, text) { + const response = await client.embeddings.create({ + input: [text], + model: embeddingsModel, + encoding_format: 'float', + }); + return response.data[0].embedding; +} + +main(); diff --git a/examples/openai/env.example b/examples/openai/env.example new file mode 100644 index 00000000..f307d178 --- /dev/null +++ b/examples/openai/env.example @@ -0,0 +1,22 @@ +# Update this with your real OpenAI API key +OPENAI_API_KEY=sk-YOUR_API_KEY + +# Uncomment to use Ollama instead of OpenAI +# OPENAI_BASE_URL=http://localhost:11434/v1 +# OPENAI_API_KEY=unused +# CHAT_MODEL=qwen2.5:0.5b +# EMBEDDINGS_MODEL=all-minilm:33m + +# OTEL_EXPORTER_* variables are not required. If you would like to change your +# OTLP endpoint to Elastic APM server using HTTP, uncomment the following: +# OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:8200 +# OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf + +OTEL_SERVICE_NAME=openai-example +OTEL_LOG_LEVEL=warn + +# Change to 'false' to hide prompt and completion content +OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true +# Change to affect behavior of which resources are detected. Note: these +# choices are specific to the runtime, in this case Node.js. +OTEL_NODE_RESOURCE_DETECTORS=container,env,host,os,serviceinstance,process,alibaba,aws,azure diff --git a/examples/openai/package.json b/examples/openai/package.json new file mode 100644 index 00000000..6b438820 --- /dev/null +++ b/examples/openai/package.json @@ -0,0 +1,24 @@ +{ + "name": "edot-node-openai-example", + "version": "1.0.0", + "private": true, + "type": "commonjs", + "engines": { + "node": ">=20" + }, + "scripts": { + "chat": "node --env-file .env --require @elastic/opentelemetry-node chat.js", + "embeddings": "node --env-file .env --require @elastic/opentelemetry-node embeddings.js" + }, + "dependencies": { + "@elastic/opentelemetry-node": "*", + "mathjs": "^14.0.1", + "openai": "^4.77.0" + }, + "// overrides comment": "Override to avoid punycode warnings in recent versions of Node.JS", + "overrides": { + "node-fetch@2.x": { + "whatwg-url": "14.x" + } + } +} From 7fbcc9cc466a393e6edbc4ba5491ca3ccfd39c83 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Jan 2025 11:45:52 +0100 Subject: [PATCH 6/6] chore(deps-dev): bump @types/node from 22.10.2 to 22.10.5 in the repo-root group (#509) --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 75a033a0..2dcfe079 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.1.0", "license": "Apache-2.0", "devDependencies": { - "@types/node": "^22.10.2", + "@types/node": "^22.10.5", "dependency-check": "^4.1.0", "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", @@ -317,9 +317,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.10.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz", - "integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==", + "version": "22.10.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.5.tgz", + "integrity": "sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ==", "dev": true, "dependencies": { "undici-types": "~6.20.0" @@ -3667,9 +3667,9 @@ "dev": true }, "@types/node": { - "version": "22.10.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz", - "integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==", + "version": "22.10.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.5.tgz", + "integrity": "sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ==", "dev": true, "requires": { "undici-types": "~6.20.0" diff --git a/package.json b/package.json index 097a4d59..2609b699 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "lint:fix": "eslint --ext=js,mjs,cjs .eslintrc.js scripts examples --fix && ls -d packages/* | while read d; do (cd $d; npm run lint:fix); done" }, "devDependencies": { - "@types/node": "^22.10.2", + "@types/node": "^22.10.5", "dependency-check": "^4.1.0", "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0",