def init_tracer(hs: "HomeServer"): """Set the whitelists and initialise the JaegerClient tracer""" global opentracing if not hs.config.opentracer_enabled: # We don't have a tracer opentracing = None return if not opentracing or not JaegerConfig: raise ConfigError( "The server has been configured to use opentracing but opentracing is not " "installed.") # Pull out the jaeger config if it was given. Otherwise set it to something sensible. # See https://github.com/jaegertracing/jaeger-client-python/blob/master/jaeger_client/config.py set_homeserver_whitelist(hs.config.opentracer_whitelist) from jaeger_client.metrics.prometheus import PrometheusMetricsFactory config = JaegerConfig( config=hs.config.jaeger_config, service_name=f"{hs.config.server_name} {hs.get_instance_name()}", scope_manager=LogContextScopeManager(hs.config), metrics_factory=PrometheusMetricsFactory(), ) # If we have the rust jaeger reporter available let's use that. if RustReporter: logger.info("Using rust_python_jaeger_reporter library") tracer = config.create_tracer(RustReporter(), config.sampler) opentracing.set_global_tracer(tracer) else: config.initialize_tracer()
def __init__(self, *args, **kwargs): # start - JAEGER config = Config(config={'sampler': {'type': 'const', 'param': 1}, 'logging': True }, service_name=__name__) config.initialize_tracer() super().__init__(*args, **kwargs)
async def notify_server_started(app, loop): config = Config(config={ 'sampler': { 'type': 'const', 'param': 1, }, 'logging': True, }, service_name="inventory", validate=True, scope_manager=ContextVarsScopeManager()) config.initialize_tracer()
def setup_service(): """ Initialize global Jaeger tracer :param config: Optional tracer configuration :return: """ service_config = config.get("jaeger", "config", fallback={'propagation': 'b3'}) # Backward compat Zipkin's B3 logger.debug("Initializing tracer with %s", service_config) tracer_config = Config(config=service_config, service_name=get_service_name(), validate=True) tracer_config.initialize_tracer()
def setup(self, host, port, component): """Setups the OpenTracing compatible tracer system. :param str host: address or host name where tracer is accepting the ingestion of the spans :param int port: the port of the tracer's ingestion endpoint :param str component: in OpenTracing terminology, service name, library, framework, etc. that generated the span """ if self._tracer_type not in ['jaeger', 'zipkin']: raise ValueError('%s tracer is not supported' % self._tracer_type) if 'jaeger' in self._tracer_type: config = Config(config={ 'local_agent': { 'reporting_host': host, 'reporting_port': port }, 'logging': True, 'sampler': { 'type': 'const', 'param': 1, }, }, service_name=component) self._tracer = config.initialize_tracer()
def initializejaeger(): # Connection to use when deploying in local # jaegerdata = load_config('../config/config.yml') # Connection to use when deploying on docker jaegerdata = load_config('config/config.yml') print(jaegerdata) config = Config(config={ 'sampler': { 'type': 'const', 'param': 1 }, 'logging': True, 'local_agent': { 'reporting_host': str(jaegerdata['jaeger']['host']), 'reporting_port': jaegerdata['jaeger']['port'] } }, service_name=str(jaegerdata['jaeger']['service_name'])) tracer = config.initialize_tracer() install_all_patches() return tracer
def main(): parser = argparse.ArgumentParser() parser.add_argument( '--log_payloads', action='store_true', default=True, help='log request/response objects to open-tracing spans') args = parser.parse_args() config = Config(config={ 'sampler': { 'type': 'const', 'param': 1, }, 'logging': True, }, service_name='hello_world_client') tracer = config.initialize_tracer() tracer_interceptor = open_tracing_client_interceptor.OpenTracingClientInterceptor( tracer, log_payloads=args.log_payloads) with tracer.start_span("step1") as span: scope.set_active_span(span) time.sleep(0.01) channel = grpc.insecure_channel(HOST_PORT) channel = grpc.intercept_channel(channel, tracer_interceptor) stub = hello_world_pb2_grpc.GreeterStub(channel) response = stub.SayHello(hello_world_pb2.HelloRequest(name='you')) print("Message received: " + response.message)
def init_tracer(): if (jaeger_logging): app.logger.info("Report log on {}:{} with app name {}".format( jaeger_host, jaeger_port, jaeger_service_name)) else: app.logger.info("Jaeger is not activated") config = Config( config={ # usually read from some yaml config 'sampler': { 'type': 'const', 'param': 1, }, 'local_agent': { 'reporting_host': jaeger_host, 'reporting_port': jaeger_port, }, 'logging': jaeger_logging, 'propagation': 'b3' }, service_name=jaeger_service_name, validate=True) opentracing_tracer = config.initialize_tracer() tracing = FlaskTracing(opentracing_tracer, True, app) return opentracing_tracer
def initialize_trace(): config = Config( config={ 'sampler': {'type': 'const', 'param': 1} }, service_name='service') return config.initialize_tracer() # also sets opentracing.tracer
def create_jaeger_tracer(configuration: Configuration = None, secrets: Secrets = None): """ Create a Jaeger tracer """ from jaeger_client.config import DEFAULT_REPORTING_PORT from jaeger_client.constants import TRACE_ID_HEADER, \ BAGGAGE_HEADER_PREFIX from jaeger_client import Config host = configuration.get("tracing_host", "localhost") port = configuration.get("tracing_port", DEFAULT_REPORTING_PORT) tracer_config = Config( config={ 'sampler': { 'type': 'const', 'param': 1, }, 'logging': True, 'propagation': configuration.get('tracing_propagation', None), 'trace_id_header': configuration.get( "tracing_id_name", TRACE_ID_HEADER), 'baggage_header_prefix': configuration.get( "baggage_prefix", BAGGAGE_HEADER_PREFIX), 'local_agent': { 'reporting_host': host, 'reporting_port': port } }, service_name='chaostoolkit', validate=True, ) addr = "{}:{}".format(host, port) logger.debug("Configured Jaeger Tracer to send to '{}'".format(addr)) return tracer_config.initialize_tracer()
def serve(): parser = argparse.ArgumentParser() parser.add_argument( '--log_payloads', action='store_true', default=True, help='log request/response objects to open-tracing spans') args = parser.parse_args() config = Config( config={ 'sampler': { 'type': 'const', 'param': 1, }, 'logging': True, }, service_name='hello_world_server') tracer = config.initialize_tracer() tracer_interceptor = open_tracing_server_interceptor.OpenTracingServerInterceptor( tracer, log_payloads=args.log_payloads) server = grpc.server( futures.ThreadPoolExecutor(max_workers=10), interceptors=(tracer_interceptor,)) hello_world_pb2_grpc.add_GreeterServicer_to_server(HelloWorld(tracer), server) server.add_insecure_port('[::]:50051') server.start() try: while True: time.sleep(_ONE_DAY_IN_SECONDS) except KeyboardInterrupt: server.stop(0)
def run(): parser = argparse.ArgumentParser() parser.add_argument( '--log_payloads', action='store_true', help='log request/response objects to open-tracing spans') args = parser.parse_args() config = Config(config={ 'sampler': { 'type': 'const', 'param': 1, }, 'logging': True, }, service_name='trivial-client') tracer = config.initialize_tracer() tracer_interceptor = open_tracing_client_interceptor( tracer, log_payloads=args.log_payloads) channel = grpc.insecure_channel('localhost:50051') channel = intercept_channel(channel, tracer_interceptor) stub = command_line_pb2.CommandLineStub(channel) response = stub.Echo(command_line_pb2.CommandRequest(text='Hello, hello')) print(response.text) time.sleep(2) tracer.close() time.sleep(2)
def new_tracer(cls, tracer_type, tracer_config, span_decorator=None, **kwargs): if not tracer_type: return Tracer() config = tracer_config.TRACING_CONFIG service_name = tracer_config.TRACING_SERVICE_NAME validate = tracer_config.TRACING_VALIDATE # if not tracer_type: # tracer_type = 'jaeger' # config = tracer_config.DEFAULT_TRACING_CONFIG if tracer_type.lower() == 'jaeger': config = Config(config=config, service_name=service_name, validate=validate) tracer = config.initialize_tracer() tracer_interceptor = open_tracing_server_interceptor( tracer, log_payloads=tracer_config.TRACING_LOG_PAYLOAD, span_decorator=span_decorator) return Tracer(tracer, tracer_interceptor, intercept_server) assert False, 'Unsupported tracer type: {}'.format(tracer_type)
def run(): parser = argparse.ArgumentParser() parser.add_argument( '--log_payloads', action='store_true', help='log request/response objects to open-tracing spans') args = parser.parse_args() config = Config(config={ 'sampler': { 'type': 'const', 'param': 1, }, 'logging': True, }, service_name='integration-client') tracer = config.initialize_tracer() active_span_source = FixedActiveSpanSource() tracer_interceptor = open_tracing_client_interceptor( tracer, active_span_source=active_span_source, log_payloads=args.log_payloads) channel = grpc.insecure_channel('localhost:50051') channel = intercept_channel(channel, tracer_interceptor) stub = command_line_pb2.CommandLineStub(channel) echo(tracer, active_span_source, stub) time.sleep(2) tracer.close() time.sleep(2)
def run(): parser = argparse.ArgumentParser() parser.add_argument( '--log_payloads', action='store_true', help='log request/response objects to open-tracing spans') args = parser.parse_args() config = Config( config={ 'sampler': { 'type': 'const', 'param': 1, }, 'logging': True, }, service_name='integration-client') tracer = config.initialize_tracer() active_span_source = FixedActiveSpanSource() tracer_interceptor = open_tracing_client_interceptor( tracer, active_span_source=active_span_source, log_payloads=args.log_payloads) channel = grpc.insecure_channel('localhost:50051') channel = intercept_channel(channel, tracer_interceptor) stub = command_line_pb2.CommandLineStub(channel) echo(tracer, active_span_source, stub) time.sleep(2) tracer.close() time.sleep(2)
def init_opentracing_tracer(tracer, **kwargs): if tracer == OPENTRACING_BASIC: from basictracer import BasicTracer # noqa recorder = kwargs.get('recorder') sampler = kwargs.get('sampler') opentracing.tracer = BasicTracer(recorder=recorder, sampler=sampler) elif tracer == OPENTRACING_INSTANA: import instana.options as InstanaOpts import instana.tracer # noqa service = kwargs.pop('service', os.environ.get('OPENTRACING_INSTANA_SERVICE')) log_level = kwargs.pop('log_level', logging.INFO) instana.tracer.init( InstanaOpts.Options(service=service, log_level=log_level, **kwargs)) elif tracer == OPENTRACING_LIGHTSTEP: import lightstep # Get Lightstep specific config vars component_name = kwargs.pop( 'component_name', os.environ.get('OPENTRACING_LIGHTSTEP_COMPONENT_NAME')) access_token = kwargs.pop( 'access_token', os.environ.get('OPENTRACING_LIGHTSTEP_ACCESS_TOKEN')) collector_host = kwargs.pop( 'collector_host', os.environ.get('OPENTRACING_LIGHTSTEP_COLLECTOR_HOST', 'collector.lightstep.com')) collector_port = kwargs.pop( 'collector_port', int(os.environ.get('OPENTRACING_LIGHTSTEP_COLLECTOR_PORT', 443))) verbosity = kwargs.pop( 'verbosity', int(os.environ.get('OPENTRACING_LIGHTSTEP_VERBOSITY', 0))) if not access_token: logger.warn('Initializing LighStep tracer with no access_token!') opentracing.tracer = lightstep.Tracer(component_name=component_name, access_token=access_token, collector_host=collector_host, collector_port=collector_port, verbosity=verbosity, **kwargs) elif tracer == OPENTRACING_JAEGER: from jaeger_client import Config service_name = kwargs.pop( 'service_name', os.environ.get('OPENTRACING_JAEGER_SERVICE_NAME')) config = kwargs.pop('config', {}) jaeger_config = Config(config=config, service_name=service_name) opentracing.tracer = jaeger_config.initialize_tracer() else: opentracing.tracer = opentracing.Tracer()
async def test_publish_injects_tracing(self): app = kafkaesk.Application(kafka_servers=["foo"]) producer = AsyncMock() producer.send.return_value = fut = asyncio.Future() fut.set_result("ok") app._get_producer = AsyncMock(return_value=producer) config = Config( config={ "sampler": { "type": "const", "param": 1 }, "logging": True, "propagation": "b3" }, service_name="test_service", scope_manager=ContextVarsScopeManager(), ) # this call also sets opentracing.tracer tracer = config.initialize_tracer() span = tracer.start_span(operation_name="dummy") tracer.scope_manager.activate(span, True) future = await app.raw_publish("foobar", b"foobar") await future headers = producer.mock_calls[0].kwargs["headers"] assert str(span).startswith(headers[0][1].decode())
def serve(): parser = argparse.ArgumentParser() parser.add_argument( '--log_payloads', action='store_true', help='log request/response objects to open-tracing spans') args = parser.parse_args() config = Config(config={ 'sampler': { 'type': 'const', 'param': 1, }, 'logging': True, }, service_name='trivial-server') tracer = config.initialize_tracer() tracer_interceptor = open_tracing_server_interceptor( tracer, log_payloads=args.log_payloads) server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) server = intercept_server(server, tracer_interceptor) command_line_pb2.add_CommandLineServicer_to_server(CommandLine(), server) server.add_insecure_port('[::]:50051') server.start() try: while True: time.sleep(_ONE_DAY_IN_SECONDS) except KeyboardInterrupt: server.stop(0) time.sleep(2) tracer.close() time.sleep(2)
def __init__(self, service='osiris_egress_api'): reporting_host = config['Jaeger Agent']['reporting_host'] reporting_port = config['Jaeger Agent']['reporting_port'] local_agent = {} # Default empty - if run on localhost if reporting_host != 'localhost': local_agent['reporting_host'] = reporting_host local_agent['reporting_port'] = reporting_port tracer_config = Config( config={ 'sampler': { 'type': 'const', 'param': 1, }, 'local_agent': local_agent, 'logging': True, }, service_name=service, validate=True, # Adds some metrics to Prometheus metrics_factory=PrometheusMetricsFactory( service_name_label='osiris_egress_api')) self.tracer = tracer_config.initialize_tracer()
def run(): config = Config( config={ "sampler": { "type": "const", "param": 1 }, "logging": True }, service_name="chat-client", ) tracer = config.initialize_tracer() active_span_source = FixedActiveSpanSource() tracer_interceptor = open_tracing_client_interceptor( tracer, active_span_source=active_span_source, log_payloads=True) channel = grpc.insecure_channel("localhost:50051") channel = intercept_channel(channel, tracer_interceptor) stub = chat_pb2_grpc.ChatStub(channel) response = list_messages(tracer, active_span_source, stub) pprint(MessageToDict(response)) time.sleep(2) tracer.close() time.sleep(2)
def create_tracer(service_name, flask_app, jaeger_host="localhost", sample_type="const", sample_param=1): """Create global flask trace instance :param service_name: current service name :param flask_app: flask app instance :param jaeger_host: jaeger agent host, default localhost :param sample_type: work with sample param reference: https://www.jaegertracing.io/docs/1.15/sampling/ :param sample_param: :return: """ config = Config(config={ 'sampler': { 'type': sample_type, 'param': sample_param }, 'local_agent': { 'reporting_host': jaeger_host } }, service_name=service_name, validate=True) jaeger_tracer = config.initialize_tracer() tracer = FlaskTracing(jaeger_tracer, True, flask_app) logging.info("Create trace {} on flask_app {} as service_name {}".format( tracer, flask_app, service_name)) return tracer
def run(): parser = argparse.ArgumentParser() parser.add_argument( '--log_payloads', action='store_true', help='log request/response objects to open-tracing spans') args = parser.parse_args() config = Config( config={ 'sampler': { 'type': 'const', 'param': 1, }, 'logging': True, }, service_name='trivial-client') tracer = config.initialize_tracer() tracer_interceptor = open_tracing_client_interceptor( tracer, log_payloads=args.log_payloads) channel = grpc.insecure_channel('localhost:50051') channel = intercept_channel(channel, tracer_interceptor) stub = command_line_pb2.CommandLineStub(channel) response = stub.Echo(command_line_pb2.CommandRequest(text='Hello, hello')) print(response.text) time.sleep(2) tracer.close() time.sleep(2)
def init_tracer(self, service, jaeger_reporting_host): logging.getLogger('').handlers = [] logging.basicConfig(format='%(message)s', level=logging.DEBUG) config = Config( config={ 'sampler': { 'type': 'const', 'param': 1, }, 'local_agent': { 'reporting_host': jaeger_reporting_host, 'reporting_port': 5775, }, 'tags': { c.JAEGER_IP_TAG_KEY: "127.0.0.1" # TODO: TempFix for ClockAdjustement issue of jaeger remove in the future! }, 'logging': True, }, service_name=service) # this call also sets opentracing.tracer self.tracer = config.initialize_tracer() print("Init Tracer") return self.tracer
def setup_opentracing(app: Sanic): if getenv("TEST_MODE"): return JAEGER_HOST = "localhost" try: JAEGER_HOST = app.config.get("JAEGER_HOST") except: pass _config = Config( config={ "sampler": { "type": "const", "param": 1 }, "logging": True, "local_agent": { "reporting_host": JAEGER_HOST }, }, service_name="bootiful_sanic", ) global TRACING global TRACER TRACER = _config.initialize_tracer() TRACING = SanicOpenTracer(tracer=TRACER, trace_all_requests=True, app=app)
def init_jaeger_tracer(service_name='proto.chat.client'): config = Config(config={'sampler': { 'type': 'const', 'param': 1, }, 'logging': True, }, service_name=service_name, validate=True) return config.initialize_tracer()
def __init__(self, config: TracerConfig): self.config = config local_agent = {} # Default empty - if run on localhost if self.config.reporting_host != 'localhost': local_agent['reporting_host'] = self.config.reporting_host local_agent['reporting_port'] = self.config.reporting_port tracer_config = Config( config={ 'sampler': { 'type': 'const', 'param': 1, }, 'local_agent': local_agent, 'logging': False, }, service_name=self.config.service_name, validate=True, ) tracer: Optional[Tracer] = tracer_config.initialize_tracer() if tracer is None: raise RuntimeError('Tracer was not initialized') self.tracer: Tracer = tracer
def serve(): config = Config( config={ "sampler": { "type": "const", "param": 1 }, "logging": True }, service_name="chat-server", ) tracer = config.initialize_tracer() tracer_interceptor = open_tracing_server_interceptor(tracer, log_payloads=True) redis_opentracing.init_tracing(tracer_interceptor) redis_client = Redis() kafka_producer = KafkaProducer( bootstrap_servers="127.0.0.1:9092", value_serializer=lambda v: json.dumps(v).encode("utf-8"), ) server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) server = intercept_server(server, tracer_interceptor) chat_pb2_grpc.add_ChatServicer_to_server( ChatServicer(tracer, redis_client, kafka_producer), server) server.add_insecure_port("[::]:50051") server.start() try: while True: time.sleep(_ONE_DAY_IN_SECONDS) except KeyboardInterrupt: server.stop(0)
def run(): parser = argparse.ArgumentParser() parser.add_argument( '--log_payloads', action='store_true', help='log request/response objects to open-tracing spans') parser.add_argument('--include_grpc_tags', action='store_true', help='set gRPC-specific tags on spans') args = parser.parse_args() config = Config(config={ 'sampler': { 'type': 'const', 'param': 1, }, 'logging': True, }, service_name='store-client') tracer = config.initialize_tracer() span_decorator = None if args.include_grpc_tags: span_decorator = StoreSpanDecorator() tracer_interceptor = open_tracing_client_interceptor( tracer, log_payloads=args.log_payloads, span_decorator=span_decorator) channel = grpc.insecure_channel('localhost:50051') channel = intercept_channel(channel, tracer_interceptor) stub = store_pb2.StoreStub(channel) read_and_execute(CommandExecuter(stub)) time.sleep(2) tracer.close() time.sleep(2)
def setup_opentracing(app): """ Helper function to setup opentracing with Jaeger client during setup. Use during app startup as follows: .. code-block:: python app = FastAPI() @app.on_event('startup') async def startup(): setup_opentracing(app) :param app: app object, instance of FastAPI :return: None """ config = Config(config={ "local_agent": { "reporting_host": settings.jaeger_host, "reporting_port": settings.jaeger_port }, "sampler": { "type": settings.jaeger_sampler_type, "param": settings.jaeger_sampler_rate, }, "trace_id_header": settings.trace_id_header }, service_name=settings.service_name, validate=True, scope_manager=AsyncioScopeManager()) # this call also sets opentracing.tracer app.tracer = config.initialize_tracer()
def setup_tracing(interface_name: str) -> object: logger.info("Initializing tracing") from jaeger_client import Config jaeger_serv = os.environ.get("JAEGER_AGENT_HOST", "0.0.0.0") jaeger_port = os.environ.get("JAEGER_AGENT_PORT", 5775) jaeger_config = os.environ.get("JAEGER_CONFIG_PATH", None) if jaeger_config is None: logger.info("Using default tracing config") config = Config( config={ # usually read from some yaml config "sampler": {"type": "const", "param": 1}, "local_agent": { "reporting_host": jaeger_serv, "reporting_port": jaeger_port, }, "logging": True, }, service_name=interface_name, validate=True, ) else: logger.info("Loading tracing config from %s", jaeger_config) import yaml with open(jaeger_config, "r") as stream: config_dict = yaml.safe_load(stream) config = Config( config=config_dict, service_name=interface_name, validate=True ) # this call also sets opentracing.tracer return config.initialize_tracer()
def init_tracer(service): logging.getLogger('').handlers = [] logging.basicConfig(format='%(message)s', level=logging.DEBUG) config = Config( config={ 'sampler': { 'type': 'const', 'param': 1, }, 'logging': True, 'reporter_batch_size': 1, }, service_name=service, ) # this call sets global variable opentracing.tracer config.initialize_tracer()
def init_tracer(service_name): JAEGER_HOST = config.JAEGER_HOST jaeger_config = Config( config={ 'sampler': { 'type': 'const', 'param': 1 }, 'logging': True, 'reporter_flush_interval': 1, 'local_agent': { 'reporting_host': JAEGER_HOST # 'reporting_host': 'localhost' } }, service_name=service_name) jaeger_config.initialize_tracer()
def init_jaeger_tracer(): logger.info('Initializing Jaeger tracer') config = Config({ 'service_name': JAEGER_SERVICE_NAME, 'sampler': { 'type': JAEGER_SAMPLING_TYPE, 'param': JAEGER_SAMPLING_PARAM, }, 'local_agent': { 'reporting_host': JAEGER_AGENT_HOST, }, 'logging': JAEGER_LOGGING_ENABLED, }, validate=True) global JAEGER_TRACER JAEGER_TRACER = config.initialize_tracer()
def serve(): parser = argparse.ArgumentParser() parser.add_argument( '--log_payloads', action='store_true', help='log request/response objects to open-tracing spans') parser.add_argument( '--include_grpc_tags', action='store_true', help='set gRPC-specific tags on spans') args = parser.parse_args() config = Config( config={ 'sampler': { 'type': 'const', 'param': 1, }, 'logging': True, }, service_name='store-server') tracer = config.initialize_tracer() span_decorator = None if args.include_grpc_tags: span_decorator = StoreSpanDecorator() tracer_interceptor = open_tracing_server_interceptor( tracer, log_payloads=args.log_payloads, span_decorator=span_decorator) server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) server = intercept_server(server, tracer_interceptor) store_pb2.add_StoreServicer_to_server(Store(), server) server.add_insecure_port('[::]:50051') server.start() try: while True: time.sleep(_ONE_DAY_IN_SECONDS) except KeyboardInterrupt: server.stop(0) time.sleep(2) tracer.close() time.sleep(2)
def test_initialize_tracer(self): c = Config({}, service_name='x') tracer = c.initialize_tracer() assert opentracing.tracer == tracer
import requests import time from opentracing_instrumentation.client_hooks import install_all_patches from jaeger_client import Config from os import getenv JAEGER_HOST = getenv('JAEGER_HOST', 'localhost') WEBSERVER_HOST = getenv('WEBSERVER_HOST', 'localhost') # Create configuration object with enabled logging and sampling of all requests. config = Config(config={'sampler': {'type': 'const', 'param': 1}, 'logging': True, 'local_agent': {'reporting_host': JAEGER_HOST}}, service_name="jaeger_opentracing_example") tracer = config.initialize_tracer() # Automatically trace all requests made with 'requests' library. install_all_patches() url = "http://{}:5000/log".format(WEBSERVER_HOST) # Make the actual request to webserver. requests.get(url) # allow tracer to flush the spans - https://github.com/jaegertracing/jaeger-client-python/issues/50 time.sleep(2) tracer.close()