We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
ddtrace.Pin() for multiple grpc channels doesn't work
Thanks for taking the time for reporting an issue!

Before reporting an issue on dd-trace-py, please be sure to provide all
necessary information.

If you're hitting a bug, make sure that you're using the latest version of this
library.

### Which version of dd-trace-py are you using?
0.38.2
I didn't find anything related to this issue in the release notes of the releases after this version.

### Which version of the libraries are you using?
datadog==0.36.0

### How can we reproduce your problem?
Approach 1:
servers is a list of grpc server addresses
```
for server in servers:
    channel = grpc.insecure_channel(server)
    Pin.override(channel, service=server)
    # Do something with the channel
```

Since `Pin.override(grpc.Channel, service=server)` worked with one server, I also tried the following to see how it looks
Approach 2:
servers is a list of grpc server addresses
```
for server in servers:
    Pin.override(grpc.Channel, service=server)
    channel = grpc.insecure_channel(server)
    # Do something with the channel
```

### What is the result that you get?
In Approach 1, Pin.override did not set the service name correctly. Everywhere in Datadog, I could see it as `grpc-client` which is the default value.
In Approach 2, since I I don't pass the channels corresponding to each server, all servers are overriden by Pin to the final server (probably because it's the last one in the loop)

### What is the result that you expected?
ddtrace.Pin() onto multiple grpc channels should work and I should be able to see the correct `service` in Datadog APM traces and Service Map

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `ddtrace/contrib/grpc/patch.py`
Content:
```
1 import os
2 
3 import grpc
4 
5 from ddtrace.vendor.wrapt import wrap_function_wrapper as _w
6 from ddtrace import config, Pin
7 
8 from ...utils.wrappers import unwrap as _u
9 
10 from . import constants
11 from .client_interceptor import create_client_interceptor, intercept_channel
12 from .server_interceptor import create_server_interceptor
13 
14 
15 config._add('grpc_server', dict(
16     service_name=config._get_service(default=constants.GRPC_SERVICE_SERVER),
17     distributed_tracing_enabled=True,
18 ))
19 
20 
21 # Precedence for the service name:
22 # 1) DD_GRPC_SERVICE if defined; or
23 # 2) For compatibility, the globally set service + "-grpc-client"; or
24 # 3) The fall-back "grpc-client"
25 if "DD_GRPC_SERVICE" in os.environ:
26     service = os.getenv("DD_GRPC_SERVICE")
27 elif config._get_service():
28     service = "{}-{}".format(config._get_service(), constants.GRPC_SERVICE_CLIENT)
29 else:
30     service = constants.GRPC_SERVICE_CLIENT
31 
32 
33 # TODO[tbutt]: keeping name for client config unchanged to maintain backwards
34 # compatibility but should change in future
35 config._add('grpc', dict(
36     service_name=service,
37     distributed_tracing_enabled=True,
38 ))
39 
40 
41 def patch():
42     _patch_client()
43     _patch_server()
44 
45 
46 def unpatch():
47     _unpatch_client()
48     _unpatch_server()
49 
50 
51 def _patch_client():
52     if getattr(constants.GRPC_PIN_MODULE_CLIENT, '__datadog_patch', False):
53         return
54     setattr(constants.GRPC_PIN_MODULE_CLIENT, '__datadog_patch', True)
55 
56     Pin().onto(constants.GRPC_PIN_MODULE_CLIENT)
57 
58     _w('grpc', 'insecure_channel', _client_channel_interceptor)
59     _w('grpc', 'secure_channel', _client_channel_interceptor)
60     _w('grpc', 'intercept_channel', intercept_channel)
61 
62 
63 def _unpatch_client():
64     if not getattr(constants.GRPC_PIN_MODULE_CLIENT, '__datadog_patch', False):
65         return
66     setattr(constants.GRPC_PIN_MODULE_CLIENT, '__datadog_patch', False)
67 
68     pin = Pin.get_from(constants.GRPC_PIN_MODULE_CLIENT)
69     if pin:
70         pin.remove_from(constants.GRPC_PIN_MODULE_CLIENT)
71 
72     _u(grpc, 'secure_channel')
73     _u(grpc, 'insecure_channel')
74 
75 
76 def _patch_server():
77     if getattr(constants.GRPC_PIN_MODULE_SERVER, '__datadog_patch', False):
78         return
79     setattr(constants.GRPC_PIN_MODULE_SERVER, '__datadog_patch', True)
80 
81     Pin().onto(constants.GRPC_PIN_MODULE_SERVER)
82 
83     _w('grpc', 'server', _server_constructor_interceptor)
84 
85 
86 def _unpatch_server():
87     if not getattr(constants.GRPC_PIN_MODULE_SERVER, '__datadog_patch', False):
88         return
89     setattr(constants.GRPC_PIN_MODULE_SERVER, '__datadog_patch', False)
90 
91     pin = Pin.get_from(constants.GRPC_PIN_MODULE_SERVER)
92     if pin:
93         pin.remove_from(constants.GRPC_PIN_MODULE_SERVER)
94 
95     _u(grpc, 'server')
96 
97 
98 def _client_channel_interceptor(wrapped, instance, args, kwargs):
99     channel = wrapped(*args, **kwargs)
100 
101     pin = Pin.get_from(constants.GRPC_PIN_MODULE_CLIENT)
102     if not pin or not pin.enabled():
103         return channel
104 
105     (host, port) = _parse_target_from_arguments(args, kwargs)
106 
107     interceptor_function = create_client_interceptor(pin, host, port)
108     return grpc.intercept_channel(channel, interceptor_function)
109 
110 
111 def _server_constructor_interceptor(wrapped, instance, args, kwargs):
112     # DEV: we clone the pin on the grpc module and configure it for the server
113     # interceptor
114 
115     pin = Pin.get_from(constants.GRPC_PIN_MODULE_SERVER)
116     if not pin or not pin.enabled():
117         return wrapped(*args, **kwargs)
118 
119     interceptor = create_server_interceptor(pin)
120 
121     # DEV: Inject our tracing interceptor first in the list of interceptors
122     if 'interceptors' in kwargs:
123         kwargs['interceptors'] = (interceptor,) + tuple(kwargs['interceptors'])
124     else:
125         kwargs['interceptors'] = (interceptor,)
126 
127     return wrapped(*args, **kwargs)
128 
129 
130 def _parse_target_from_arguments(args, kwargs):
131     if 'target' in kwargs:
132         target = kwargs['target']
133     else:
134         target = args[0]
135 
136     split = target.rsplit(':', 2)
137 
138     return (split[0], split[1] if len(split) > 1 else None)
139
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/ddtrace/contrib/grpc/patch.py b/ddtrace/contrib/grpc/patch.py
--- a/ddtrace/contrib/grpc/patch.py
+++ b/ddtrace/contrib/grpc/patch.py
@@ -98,7 +98,7 @@
 def _client_channel_interceptor(wrapped, instance, args, kwargs):
     channel = wrapped(*args, **kwargs)
 
-    pin = Pin.get_from(constants.GRPC_PIN_MODULE_CLIENT)
+    pin = Pin.get_from(channel)
     if not pin or not pin.enabled():
         return channel

{"golden_diff": "diff --git a/ddtrace/contrib/grpc/patch.py b/ddtrace/contrib/grpc/patch.py\n--- a/ddtrace/contrib/grpc/patch.py\n+++ b/ddtrace/contrib/grpc/patch.py\n@@ -98,7 +98,7 @@\n def _client_channel_interceptor(wrapped, instance, args, kwargs):\n     channel = wrapped(*args, **kwargs)\n \n-    pin = Pin.get_from(constants.GRPC_PIN_MODULE_CLIENT)\n+    pin = Pin.get_from(channel)\n     if not pin or not pin.enabled():\n         return channel\n", "issue": "ddtrace.Pin() for multiple grpc channels doesn't work\nThanks for taking the time for reporting an issue!\r\n\r\nBefore reporting an issue on dd-trace-py, please be sure to provide all\r\nnecessary information.\r\n\r\nIf you're hitting a bug, make sure that you're using the latest version of this\r\nlibrary.\r\n\r\n### Which version of dd-trace-py are you using?\r\n0.38.2\r\nI didn't find anything related to this issue in the release notes of the releases after this version.\r\n\r\n### Which version of the libraries are you using?\r\ndatadog==0.36.0\r\n\r\n### How can we reproduce your problem?\r\nApproach 1:\r\nservers is a list of grpc server addresses\r\n```\r\nfor server in servers:\r\n    channel = grpc.insecure_channel(server)\r\n    Pin.override(channel, service=server)\r\n    # Do something with the channel\r\n```\r\n\r\nSince `Pin.override(grpc.Channel, service=server)` worked with one server, I also tried the following to see how it looks\r\nApproach 2:\r\nservers is a list of grpc server addresses\r\n```\r\nfor server in servers:\r\n    Pin.override(grpc.Channel, service=server)\r\n    channel = grpc.insecure_channel(server)\r\n    # Do something with the channel\r\n```\r\n\r\n### What is the result that you get?\r\nIn Approach 1, Pin.override did not set the service name correctly. Everywhere in Datadog, I could see it as `grpc-client` which is the default value.\r\nIn Approach 2, since I I don't pass the channels corresponding to each server, all servers are overriden by Pin to the final server (probably because it's the last one in the loop)\r\n\r\n### What is the result that you expected?\r\nddtrace.Pin() onto multiple grpc channels should work and I should be able to see the correct `service` in Datadog APM traces and Service Map\n", "before_files": [{"content": "import os\n\nimport grpc\n\nfrom ddtrace.vendor.wrapt import wrap_function_wrapper as _w\nfrom ddtrace import config, Pin\n\nfrom ...utils.wrappers import unwrap as _u\n\nfrom . import constants\nfrom .client_interceptor import create_client_interceptor, intercept_channel\nfrom .server_interceptor import create_server_interceptor\n\n\nconfig._add('grpc_server', dict(\n    service_name=config._get_service(default=constants.GRPC_SERVICE_SERVER),\n    distributed_tracing_enabled=True,\n))\n\n\n# Precedence for the service name:\n# 1) DD_GRPC_SERVICE if defined; or\n# 2) For compatibility, the globally set service + \"-grpc-client\"; or\n# 3) The fall-back \"grpc-client\"\nif \"DD_GRPC_SERVICE\" in os.environ:\n    service = os.getenv(\"DD_GRPC_SERVICE\")\nelif config._get_service():\n    service = \"{}-{}\".format(config._get_service(), constants.GRPC_SERVICE_CLIENT)\nelse:\n    service = constants.GRPC_SERVICE_CLIENT\n\n\n# TODO[tbutt]: keeping name for client config unchanged to maintain backwards\n# compatibility but should change in future\nconfig._add('grpc', dict(\n    service_name=service,\n    distributed_tracing_enabled=True,\n))\n\n\ndef patch():\n    _patch_client()\n    _patch_server()\n\n\ndef unpatch():\n    _unpatch_client()\n    _unpatch_server()\n\n\ndef _patch_client():\n    if getattr(constants.GRPC_PIN_MODULE_CLIENT, '__datadog_patch', False):\n        return\n    setattr(constants.GRPC_PIN_MODULE_CLIENT, '__datadog_patch', True)\n\n    Pin().onto(constants.GRPC_PIN_MODULE_CLIENT)\n\n    _w('grpc', 'insecure_channel', _client_channel_interceptor)\n    _w('grpc', 'secure_channel', _client_channel_interceptor)\n    _w('grpc', 'intercept_channel', intercept_channel)\n\n\ndef _unpatch_client():\n    if not getattr(constants.GRPC_PIN_MODULE_CLIENT, '__datadog_patch', False):\n        return\n    setattr(constants.GRPC_PIN_MODULE_CLIENT, '__datadog_patch', False)\n\n    pin = Pin.get_from(constants.GRPC_PIN_MODULE_CLIENT)\n    if pin:\n        pin.remove_from(constants.GRPC_PIN_MODULE_CLIENT)\n\n    _u(grpc, 'secure_channel')\n    _u(grpc, 'insecure_channel')\n\n\ndef _patch_server():\n    if getattr(constants.GRPC_PIN_MODULE_SERVER, '__datadog_patch', False):\n        return\n    setattr(constants.GRPC_PIN_MODULE_SERVER, '__datadog_patch', True)\n\n    Pin().onto(constants.GRPC_PIN_MODULE_SERVER)\n\n    _w('grpc', 'server', _server_constructor_interceptor)\n\n\ndef _unpatch_server():\n    if not getattr(constants.GRPC_PIN_MODULE_SERVER, '__datadog_patch', False):\n        return\n    setattr(constants.GRPC_PIN_MODULE_SERVER, '__datadog_patch', False)\n\n    pin = Pin.get_from(constants.GRPC_PIN_MODULE_SERVER)\n    if pin:\n        pin.remove_from(constants.GRPC_PIN_MODULE_SERVER)\n\n    _u(grpc, 'server')\n\n\ndef _client_channel_interceptor(wrapped, instance, args, kwargs):\n    channel = wrapped(*args, **kwargs)\n\n    pin = Pin.get_from(constants.GRPC_PIN_MODULE_CLIENT)\n    if not pin or not pin.enabled():\n        return channel\n\n    (host, port) = _parse_target_from_arguments(args, kwargs)\n\n    interceptor_function = create_client_interceptor(pin, host, port)\n    return grpc.intercept_channel(channel, interceptor_function)\n\n\ndef _server_constructor_interceptor(wrapped, instance, args, kwargs):\n    # DEV: we clone the pin on the grpc module and configure it for the server\n    # interceptor\n\n    pin = Pin.get_from(constants.GRPC_PIN_MODULE_SERVER)\n    if not pin or not pin.enabled():\n        return wrapped(*args, **kwargs)\n\n    interceptor = create_server_interceptor(pin)\n\n    # DEV: Inject our tracing interceptor first in the list of interceptors\n    if 'interceptors' in kwargs:\n        kwargs['interceptors'] = (interceptor,) + tuple(kwargs['interceptors'])\n    else:\n        kwargs['interceptors'] = (interceptor,)\n\n    return wrapped(*args, **kwargs)\n\n\ndef _parse_target_from_arguments(args, kwargs):\n    if 'target' in kwargs:\n        target = kwargs['target']\n    else:\n        target = args[0]\n\n    split = target.rsplit(':', 2)\n\n    return (split[0], split[1] if len(split) > 1 else None)\n", "path": "ddtrace/contrib/grpc/patch.py"}], "after_files": [{"content": "import os\n\nimport grpc\n\nfrom ddtrace.vendor.wrapt import wrap_function_wrapper as _w\nfrom ddtrace import config, Pin\n\nfrom ...utils.wrappers import unwrap as _u\n\nfrom . import constants\nfrom .client_interceptor import create_client_interceptor, intercept_channel\nfrom .server_interceptor import create_server_interceptor\n\n\nconfig._add('grpc_server', dict(\n    service_name=config._get_service(default=constants.GRPC_SERVICE_SERVER),\n    distributed_tracing_enabled=True,\n))\n\n\n# Precedence for the service name:\n# 1) DD_GRPC_SERVICE if defined; or\n# 2) For compatibility, the globally set service + \"-grpc-client\"; or\n# 3) The fall-back \"grpc-client\"\nif \"DD_GRPC_SERVICE\" in os.environ:\n    service = os.getenv(\"DD_GRPC_SERVICE\")\nelif config._get_service():\n    service = \"{}-{}\".format(config._get_service(), constants.GRPC_SERVICE_CLIENT)\nelse:\n    service = constants.GRPC_SERVICE_CLIENT\n\n\n# TODO[tbutt]: keeping name for client config unchanged to maintain backwards\n# compatibility but should change in future\nconfig._add('grpc', dict(\n    service_name=service,\n    distributed_tracing_enabled=True,\n))\n\n\ndef patch():\n    _patch_client()\n    _patch_server()\n\n\ndef unpatch():\n    _unpatch_client()\n    _unpatch_server()\n\n\ndef _patch_client():\n    if getattr(constants.GRPC_PIN_MODULE_CLIENT, '__datadog_patch', False):\n        return\n    setattr(constants.GRPC_PIN_MODULE_CLIENT, '__datadog_patch', True)\n\n    Pin().onto(constants.GRPC_PIN_MODULE_CLIENT)\n\n    _w('grpc', 'insecure_channel', _client_channel_interceptor)\n    _w('grpc', 'secure_channel', _client_channel_interceptor)\n    _w('grpc', 'intercept_channel', intercept_channel)\n\n\ndef _unpatch_client():\n    if not getattr(constants.GRPC_PIN_MODULE_CLIENT, '__datadog_patch', False):\n        return\n    setattr(constants.GRPC_PIN_MODULE_CLIENT, '__datadog_patch', False)\n\n    pin = Pin.get_from(constants.GRPC_PIN_MODULE_CLIENT)\n    if pin:\n        pin.remove_from(constants.GRPC_PIN_MODULE_CLIENT)\n\n    _u(grpc, 'secure_channel')\n    _u(grpc, 'insecure_channel')\n\n\ndef _patch_server():\n    if getattr(constants.GRPC_PIN_MODULE_SERVER, '__datadog_patch', False):\n        return\n    setattr(constants.GRPC_PIN_MODULE_SERVER, '__datadog_patch', True)\n\n    Pin().onto(constants.GRPC_PIN_MODULE_SERVER)\n\n    _w('grpc', 'server', _server_constructor_interceptor)\n\n\ndef _unpatch_server():\n    if not getattr(constants.GRPC_PIN_MODULE_SERVER, '__datadog_patch', False):\n        return\n    setattr(constants.GRPC_PIN_MODULE_SERVER, '__datadog_patch', False)\n\n    pin = Pin.get_from(constants.GRPC_PIN_MODULE_SERVER)\n    if pin:\n        pin.remove_from(constants.GRPC_PIN_MODULE_SERVER)\n\n    _u(grpc, 'server')\n\n\ndef _client_channel_interceptor(wrapped, instance, args, kwargs):\n    channel = wrapped(*args, **kwargs)\n\n    pin = Pin.get_from(channel)\n    if not pin or not pin.enabled():\n        return channel\n\n    (host, port) = _parse_target_from_arguments(args, kwargs)\n\n    interceptor_function = create_client_interceptor(pin, host, port)\n    return grpc.intercept_channel(channel, interceptor_function)\n\n\ndef _server_constructor_interceptor(wrapped, instance, args, kwargs):\n    # DEV: we clone the pin on the grpc module and configure it for the server\n    # interceptor\n\n    pin = Pin.get_from(constants.GRPC_PIN_MODULE_SERVER)\n    if not pin or not pin.enabled():\n        return wrapped(*args, **kwargs)\n\n    interceptor = create_server_interceptor(pin)\n\n    # DEV: Inject our tracing interceptor first in the list of interceptors\n    if 'interceptors' in kwargs:\n        kwargs['interceptors'] = (interceptor,) + tuple(kwargs['interceptors'])\n    else:\n        kwargs['interceptors'] = (interceptor,)\n\n    return wrapped(*args, **kwargs)\n\n\ndef _parse_target_from_arguments(args, kwargs):\n    if 'target' in kwargs:\n        target = kwargs['target']\n    else:\n        target = args[0]\n\n    split = target.rsplit(':', 2)\n\n    return (split[0], split[1] if len(split) > 1 else None)\n", "path": "ddtrace/contrib/grpc/patch.py"}]}