Repository: open-telemetry/opentelemetry-python-contrib

Issue:
opentelemetry-instrumentation-grpc fails if client channel is used as a context manager
**Describe your environment**

Verified on python 3.8.6 with opentelemetry 0.17b0

**Steps to reproduce**

Use a gRPC channel as a context manager.

For instance, this happens if you add instrumentation to the [gRPC helloworld example client](https://github.com/grpc/grpc/tree/026046d84301999936a759c1779669c04c6ffaaa/examples/python/helloworld):

```py
# Copyright 2015 gRPC authors.
#
# Licensed 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.
"""The Python implementation of the GRPC helloworld.Greeter client."""

from __future__ import print_function
import logging

import grpc

from opentelemetry import trace
from opentelemetry.instrumentation.grpc import GrpcInstrumentorClient
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import (
    ConsoleSpanExporter,
    SimpleExportSpanProcessor,
)

import helloworld_pb2
import helloworld_pb2_grpc

trace.set_tracer_provider(TracerProvider())
trace.get_tracer_provider().add_span_processor(
    SimpleExportSpanProcessor(ConsoleSpanExporter())
)

GrpcInstrumentorClient().instrument()


def run():
    # NOTE(gRPC Python Team): .close() is possible on a channel and should be
    # used in circumstances in which the with statement does not fit the needs
    # of the code.
    with grpc.insecure_channel('localhost:50051') as channel:
        stub = helloworld_pb2_grpc.GreeterStub(channel)
        response = stub.SayHello(helloworld_pb2.HelloRequest(name='you'))
        print("Greeter client received: " + response.message)


if __name__ == '__main__':
    logging.basicConfig()
    run()
```

**What is the expected behavior?**

The channel should be usable as normal, except now with instrumentation

**What is the actual behavior?**

```
❯ python greeter_client.py
Traceback (most recent call last):
  File "greeter_client.py", line 52, in <module>
    run()
  File "greeter_client.py", line 44, in run
    with grpc.insecure_channel('localhost:50051') as channel:
  File "/home/isobel/workspace/tmp/otlp/grpc/lib/python3.8/site-packages/opentelemetry/instrumentation/grpc/grpcext/_interceptor.py", line 235, in __enter__
    raise NotImplementedError()
NotImplementedError
```

**Additional context**

LMK and I can make a PR


Discussion:
I did a lot of testing with this (see recent PRs) but apparently never once tried a channel as a context manager - all of my production code saves the channel in a client class instead.  Good catch!

Resolving patch:
diff --git a/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/grpcext/_interceptor.py b/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/grpcext/_interceptor.py
--- a/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/grpcext/_interceptor.py
+++ b/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/grpcext/_interceptor.py
@@ -232,11 +232,11 @@ def close(self):
 
     def __enter__(self):
         """Enters the runtime context related to the channel object."""
-        raise NotImplementedError()
+        return self
 
     def __exit__(self, exc_type, exc_val, exc_tb):
         """Exits the runtime context related to the channel object."""
-        raise NotImplementedError()
+        self.close()
 
 
 def intercept_channel(channel, *interceptors):


Test patch: