Skip to content

Commit f34f183

Browse files
chore(langchain/openai): enable service naming [backport 1.17] (#6444)
Backport 7d675fd from #6407 to 1.17. This change updates the langchain and openai contribs to support schematized service names. == Special Note == These changes are gated behind a feature flag and are not expected to be stable until a release note is generated. Existing customers should be unaffected. == Service Naming Summary == Datadog is updating its method of determining service names! Service naming introduces a few concepts: * Versioned service name "schemas": * v0: The existing mechanism for determining service names * v1: Replacing the 'default' contrib-specific service name with the env var $DD_SERVICE These changes are being in conjunction with changes to peer.service updates to bring a better service-naming experience to customers. In particular, these changes will help: * Remove the creation of fake services, such as grpc.client * Standardize service names across and within tracers * Remove the need to create as many fake services to take advantage of Datadog features, such as metrics * Make more sense to humans == Operation Naming Summary == The service name changes mean that generated spans can no longer rely on `span.service` to differentiate between processes. A subclass of spans now have a new problem - differentiating between inbound and outbound requests (for the purposes of metrics). For instance, spans with names `http.request` used to be differentiated by the service they belonged to (incoming requests under `span.service=$DD_SERVICE` and outgoing under `span.service=$DD_CONTRIB_SERVICE_NAME`). These are now no longer differentiated. To remedy these issues, operation names are also being changed as part of the service naming effort. In the above example, `http.request` turns into `http.server.request` (incoming) and `http.client.request` (outgoing). ## Checklist - [x] Change(s) are motivated and described in the PR description. - [x] Testing strategy is described if automated tests are not included in the PR. - [x] Risk is outlined (performance impact, potential for breakage, maintainability, etc). - [x] Change is maintainable (easy to change, telemetry, documentation). - [x] [Library release note guidelines](https://ddtrace.readthedocs.io/en/stable/releasenotes.html) are followed. If no release note is required, add label `changelog/no-changelog`. - [x] Documentation is included (in-code, generated user docs, [public corp docs](https://github.com/DataDog/documentation/)). - [x] Backport labels are set (if [applicable](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting)) ## Reviewer Checklist - [x] Title is accurate. - [x] No unnecessary changes are introduced. - [x] Description motivates each change. - [x] Avoids breaking [API](https://ddtrace.readthedocs.io/en/stable/versioning.html#interfaces) changes unless absolutely necessary. - [x] Testing strategy adequately addresses listed risk(s). - [x] Change is maintainable (easy to change, telemetry, documentation). - [x] Release note makes sense to a user of the library. - [x] Reviewer has explicitly acknowledged and discussed the performance implications of this PR as reported in the benchmarks PR comment. - [x] Backport labels are set in a manner that is consistent with the [release branch maintenance policy](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting) Co-authored-by: Teague Bick <[email protected]>
1 parent d4e248a commit f34f183

15 files changed

+1170
-1
lines changed

ddtrace/contrib/openai/patch.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from ddtrace.internal.agent import get_stats_url
99
from ddtrace.internal.constants import COMPONENT
1010
from ddtrace.internal.logger import get_logger
11+
from ddtrace.internal.schema import schematize_service_name
1112
from ddtrace.internal.utils.formats import asbool
1213
from ddtrace.internal.wrapping import wrap
1314

@@ -333,7 +334,8 @@ def _patched_make_session(func, args, kwargs):
333334
This should technically be a ``peer.service`` but this concept doesn't exist yet.
334335
"""
335336
session = func(*args, **kwargs)
336-
Pin.override(session, service="openai")
337+
service = schematize_service_name("openai")
338+
Pin.override(session, service=service)
337339
return session
338340

339341

tests/contrib/langchain/test_langchain.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1285,6 +1285,46 @@ def test_openai_integration(langchain, request_vcr, ddtrace_run_python_code_in_s
12851285
assert err == b""
12861286

12871287

1288+
@pytest.mark.skipif(sys.version_info < (3, 10, 0), reason="Requires unnecessary cassette file for Python 3.9")
1289+
@pytest.mark.snapshot(ignores=["metrics.langchain.tokens.total_cost"])
1290+
@pytest.mark.parametrize("schema_version", [None, "v0", "v1"])
1291+
@pytest.mark.parametrize("service_name", [None, "mysvc"])
1292+
def test_openai_service_name(
1293+
langchain, request_vcr, ddtrace_run_python_code_in_subprocess, schema_version, service_name
1294+
):
1295+
env = os.environ.copy()
1296+
pypath = [os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))]
1297+
if "PYTHONPATH" in env:
1298+
pypath.append(env["PYTHONPATH"])
1299+
env.update(
1300+
{
1301+
"PYTHONPATH": ":".join(pypath),
1302+
# Disable metrics because the test agent doesn't support metrics
1303+
"DD_LANGCHAIN_METRICS_ENABLED": "false",
1304+
"DD_OPENAI_METRICS_ENABLED": "false",
1305+
"OPENAI_API_KEY": "<not-a-real-key>",
1306+
}
1307+
)
1308+
if service_name:
1309+
env["DD_SERVICE"] = service_name
1310+
if schema_version:
1311+
env["DD_TRACE_SPAN_ATTRIBUTE_SCHEMA"] = schema_version
1312+
out, err, status, pid = ddtrace_run_python_code_in_subprocess(
1313+
"""
1314+
from langchain.llms import OpenAI
1315+
import ddtrace
1316+
from tests.contrib.langchain.test_langchain import get_request_vcr
1317+
llm = OpenAI()
1318+
with get_request_vcr().use_cassette("openai_completion_sync.yaml"):
1319+
llm("Can you explain what Descartes meant by 'I think, therefore I am'?")
1320+
""",
1321+
env=env,
1322+
)
1323+
assert status == 0, err
1324+
assert out == b""
1325+
assert err == b""
1326+
1327+
12881328
@pytest.mark.parametrize(
12891329
"ddtrace_config_langchain",
12901330
[

tests/contrib/openai/test_openai.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2092,3 +2092,40 @@ def test_est_tokens():
20922092
)
20932093
== 97
20942094
) # oracle: 92
2095+
2096+
2097+
@pytest.mark.snapshot(ignores=["meta.http.useragent"], async_mode=False)
2098+
@pytest.mark.parametrize("schema_version", [None, "v0", "v1"])
2099+
@pytest.mark.parametrize("service_name", [None, "mysvc"])
2100+
def test_integration_service_name(openai_api_key, ddtrace_run_python_code_in_subprocess, schema_version, service_name):
2101+
env = os.environ.copy()
2102+
pypath = [os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))]
2103+
if "PYTHONPATH" in env:
2104+
pypath.append(env["PYTHONPATH"])
2105+
env.update(
2106+
{
2107+
"OPENAI_API_KEY": openai_api_key,
2108+
"PYTHONPATH": ":".join(pypath),
2109+
# Disable metrics because the test agent doesn't support metrics
2110+
"DD_OPENAI_METRICS_ENABLED": "false",
2111+
}
2112+
)
2113+
if schema_version:
2114+
env["DD_TRACE_SPAN_ATTRIBUTE_SCHEMA"] = schema_version
2115+
if service_name:
2116+
env["DD_SERVICE"] = service_name
2117+
out, err, status, pid = ddtrace_run_python_code_in_subprocess(
2118+
"""
2119+
import openai
2120+
import ddtrace
2121+
from tests.contrib.openai.test_openai import FilterOrg, get_openai_vcr
2122+
pin = ddtrace.Pin.get_from(openai)
2123+
pin.tracer.configure(settings={"FILTERS": [FilterOrg()]})
2124+
with get_openai_vcr().use_cassette("completion_2.yaml"):
2125+
resp = openai.Completion.create(model="ada", prompt="hello world")
2126+
""",
2127+
env=env,
2128+
)
2129+
assert status == 0, err
2130+
assert out == b""
2131+
assert err == b""
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
[[
2+
{
3+
"name": "langchain.request",
4+
"service": "",
5+
"resource": "langchain.llms.openai.OpenAI",
6+
"trace_id": 0,
7+
"span_id": 1,
8+
"parent_id": 0,
9+
"type": "",
10+
"error": 0,
11+
"meta": {
12+
"_dd.p.dm": "-0",
13+
"langchain.request.api_key": "...key>",
14+
"langchain.request.model": "text-davinci-003",
15+
"langchain.request.openai.parameters.frequency_penalty": "0",
16+
"langchain.request.openai.parameters.max_tokens": "256",
17+
"langchain.request.openai.parameters.model_name": "text-davinci-003",
18+
"langchain.request.openai.parameters.n": "1",
19+
"langchain.request.openai.parameters.presence_penalty": "0",
20+
"langchain.request.openai.parameters.request_timeout": "None",
21+
"langchain.request.openai.parameters.temperature": "0.7",
22+
"langchain.request.openai.parameters.top_p": "1",
23+
"langchain.request.prompts.0": "Can you explain what Descartes meant by 'I think, therefore I am'?",
24+
"langchain.request.provider": "openai",
25+
"langchain.request.type": "llm",
26+
"langchain.response.completions.0.finish_reason": "stop",
27+
"langchain.response.completions.0.logprobs": "None",
28+
"langchain.response.completions.0.text": "\\n\\nDescartes' famous phrase \"I think, therefore I am\" is a fundamental statement of his philosophical approach, known as Cartes...",
29+
"language": "python",
30+
"runtime-id": "d24e6145724d4113a14c083bbe74f8bf"
31+
},
32+
"metrics": {
33+
"_dd.agent_psr": 1.0,
34+
"_dd.measured": 1,
35+
"_dd.top_level": 1,
36+
"_dd.tracer_kr": 1.0,
37+
"_sampling_priority_v1": 1,
38+
"langchain.tokens.completion_tokens": 95,
39+
"langchain.tokens.prompt_tokens": 17,
40+
"langchain.tokens.total_cost": 0.0022400000000000002,
41+
"langchain.tokens.total_tokens": 112,
42+
"process_id": 1184
43+
},
44+
"duration": 9396250,
45+
"start": 1689781623043723458
46+
},
47+
{
48+
"name": "openai.request",
49+
"service": "",
50+
"resource": "createCompletion",
51+
"trace_id": 0,
52+
"span_id": 2,
53+
"parent_id": 1,
54+
"type": "",
55+
"error": 0,
56+
"meta": {
57+
"component": "openai",
58+
"openai.api_base": "https://api.openai.com/v1",
59+
"openai.api_type": "open_ai",
60+
"openai.organization.name": "datadog-4",
61+
"openai.request.endpoint": "/v1/completions",
62+
"openai.request.frequency_penalty": "0",
63+
"openai.request.max_tokens": "256",
64+
"openai.request.method": "POST",
65+
"openai.request.model": "text-davinci-003",
66+
"openai.request.n": "1",
67+
"openai.request.presence_penalty": "0",
68+
"openai.request.prompt.0": "Can you explain what Descartes meant by 'I think, therefore I am'?",
69+
"openai.request.temperature": "0.7",
70+
"openai.request.top_p": "1",
71+
"openai.response.choices.0.finish_reason": "stop",
72+
"openai.response.choices.0.logprobs": "returned",
73+
"openai.response.choices.0.text": "\\n\\nDescartes' famous phrase \"I think, therefore I am\" is a fundamental statement of his philosophical approach, known as Cartes...",
74+
"openai.response.id": "cmpl-7TZs9SoIjYLVNCYmAqIz9ihMX1grP",
75+
"openai.response.model": "text-davinci-003",
76+
"openai.user.api_key": "sk-...key>"
77+
},
78+
"metrics": {
79+
"_dd.measured": 1,
80+
"openai.organization.ratelimit.requests.remaining": 2999,
81+
"openai.organization.ratelimit.tokens.remaining": 249744,
82+
"openai.response.choices_count": 1,
83+
"openai.response.created": 1687283761
84+
},
85+
"duration": 8934709,
86+
"start": 1689781623044016166
87+
},
88+
{
89+
"name": "requests.request",
90+
"service": "openai",
91+
"resource": "requests.request",
92+
"trace_id": 0,
93+
"span_id": 3,
94+
"parent_id": 2,
95+
"type": "http",
96+
"error": 0,
97+
"meta": {
98+
"component": "requests",
99+
"http.method": "POST",
100+
"http.status_code": "200",
101+
"http.url": "https://api.openai.com/v1/completions",
102+
"http.useragent": "OpenAI/v1 PythonBindings/0.27.8",
103+
"out.host": "api.openai.com",
104+
"span.kind": "client"
105+
},
106+
"metrics": {
107+
"_dd.measured": 1,
108+
"_dd.top_level": 1
109+
},
110+
"duration": 2049792,
111+
"start": 1689781623047737333
112+
}]]
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
[[
2+
{
3+
"name": "langchain.request",
4+
"service": "",
5+
"resource": "langchain.llms.openai.OpenAI",
6+
"trace_id": 0,
7+
"span_id": 1,
8+
"parent_id": 0,
9+
"type": "",
10+
"error": 0,
11+
"meta": {
12+
"_dd.p.dm": "-0",
13+
"langchain.request.api_key": "...key>",
14+
"langchain.request.model": "text-davinci-003",
15+
"langchain.request.openai.parameters.frequency_penalty": "0",
16+
"langchain.request.openai.parameters.max_tokens": "256",
17+
"langchain.request.openai.parameters.model_name": "text-davinci-003",
18+
"langchain.request.openai.parameters.n": "1",
19+
"langchain.request.openai.parameters.presence_penalty": "0",
20+
"langchain.request.openai.parameters.request_timeout": "None",
21+
"langchain.request.openai.parameters.temperature": "0.7",
22+
"langchain.request.openai.parameters.top_p": "1",
23+
"langchain.request.prompts.0": "Can you explain what Descartes meant by 'I think, therefore I am'?",
24+
"langchain.request.provider": "openai",
25+
"langchain.request.type": "llm",
26+
"langchain.response.completions.0.finish_reason": "stop",
27+
"langchain.response.completions.0.logprobs": "None",
28+
"langchain.response.completions.0.text": "\\n\\nDescartes' famous phrase \"I think, therefore I am\" is a fundamental statement of his philosophical approach, known as Cartes...",
29+
"language": "python",
30+
"runtime-id": "ab50b44eb3054abf9bc73864166b5721"
31+
},
32+
"metrics": {
33+
"_dd.agent_psr": 1.0,
34+
"_dd.measured": 1,
35+
"_dd.top_level": 1,
36+
"_dd.tracer_kr": 1.0,
37+
"_sampling_priority_v1": 1,
38+
"langchain.tokens.completion_tokens": 95,
39+
"langchain.tokens.prompt_tokens": 17,
40+
"langchain.tokens.total_cost": 0.0022400000000000002,
41+
"langchain.tokens.total_tokens": 112,
42+
"process_id": 1197
43+
},
44+
"duration": 9884916,
45+
"start": 1689781625795789668
46+
},
47+
{
48+
"name": "openai.request",
49+
"service": "",
50+
"resource": "createCompletion",
51+
"trace_id": 0,
52+
"span_id": 2,
53+
"parent_id": 1,
54+
"type": "",
55+
"error": 0,
56+
"meta": {
57+
"component": "openai",
58+
"openai.api_base": "https://api.openai.com/v1",
59+
"openai.api_type": "open_ai",
60+
"openai.organization.name": "datadog-4",
61+
"openai.request.endpoint": "/v1/completions",
62+
"openai.request.frequency_penalty": "0",
63+
"openai.request.max_tokens": "256",
64+
"openai.request.method": "POST",
65+
"openai.request.model": "text-davinci-003",
66+
"openai.request.n": "1",
67+
"openai.request.presence_penalty": "0",
68+
"openai.request.prompt.0": "Can you explain what Descartes meant by 'I think, therefore I am'?",
69+
"openai.request.temperature": "0.7",
70+
"openai.request.top_p": "1",
71+
"openai.response.choices.0.finish_reason": "stop",
72+
"openai.response.choices.0.logprobs": "returned",
73+
"openai.response.choices.0.text": "\\n\\nDescartes' famous phrase \"I think, therefore I am\" is a fundamental statement of his philosophical approach, known as Cartes...",
74+
"openai.response.id": "cmpl-7TZs9SoIjYLVNCYmAqIz9ihMX1grP",
75+
"openai.response.model": "text-davinci-003",
76+
"openai.user.api_key": "sk-...key>"
77+
},
78+
"metrics": {
79+
"_dd.measured": 1,
80+
"openai.organization.ratelimit.requests.remaining": 2999,
81+
"openai.organization.ratelimit.tokens.remaining": 249744,
82+
"openai.response.choices_count": 1,
83+
"openai.response.created": 1687283761
84+
},
85+
"duration": 9303209,
86+
"start": 1689781625796142209
87+
},
88+
{
89+
"name": "requests.request",
90+
"service": "openai",
91+
"resource": "requests.request",
92+
"trace_id": 0,
93+
"span_id": 3,
94+
"parent_id": 2,
95+
"type": "http",
96+
"error": 0,
97+
"meta": {
98+
"component": "requests",
99+
"http.method": "POST",
100+
"http.status_code": "200",
101+
"http.url": "https://api.openai.com/v1/completions",
102+
"http.useragent": "OpenAI/v1 PythonBindings/0.27.8",
103+
"out.host": "api.openai.com",
104+
"span.kind": "client"
105+
},
106+
"metrics": {
107+
"_dd.measured": 1,
108+
"_dd.top_level": 1
109+
},
110+
"duration": 2005833,
111+
"start": 1689781625799821543
112+
}]]

0 commit comments

Comments
 (0)