github.com/newrelic/go-agent@v3.26.0+incompatible/examples/custom-instrumentation/main.go (about)

     1  // Copyright 2020 New Relic Corporation. All rights reserved.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  // An application that illustrates Distributed Tracing with custom
     5  // instrumentation.
     6  //
     7  // This application simulates simple inter-process communication between a
     8  // calling and a called process.
     9  //
    10  // Invoked without arguments, the application acts as a calling process;
    11  // invoked with one argument representing a payload, it acts as a called
    12  // process. The calling process creates a payload, starts a called process and
    13  // passes on the payload. The calling process waits until the called process is
    14  // done and then terminates. Thus to start both processes, only a single
    15  // invocation of the application (without any arguments) is needed.
    16  package main
    17  
    18  import (
    19  	"fmt"
    20  	"os"
    21  	"os/exec"
    22  	"time"
    23  
    24  	"github.com/newrelic/go-agent"
    25  )
    26  
    27  func mustGetEnv(key string) string {
    28  	if val := os.Getenv(key); "" != val {
    29  		return val
    30  	}
    31  	panic(fmt.Sprintf("environment variable %s unset", key))
    32  }
    33  
    34  func called(app newrelic.Application, payload string) {
    35  	txn := app.StartTransaction("called-txn", nil, nil)
    36  	defer txn.End()
    37  
    38  	// Accept the payload that was passed on the command line.
    39  	txn.AcceptDistributedTracePayload(newrelic.TransportOther, payload)
    40  	time.Sleep(1 * time.Second)
    41  }
    42  
    43  func calling(app newrelic.Application) {
    44  	txn := app.StartTransaction("calling-txn", nil, nil)
    45  	defer txn.End()
    46  
    47  	// Create a payload, start the called process and pass the payload.
    48  	payload := txn.CreateDistributedTracePayload()
    49  	cmd := exec.Command(os.Args[0], payload.Text())
    50  	cmd.Start()
    51  
    52  	// Wait until the called process is done, then exit.
    53  	cmd.Wait()
    54  	time.Sleep(1 * time.Second)
    55  }
    56  
    57  func makeApplication(name string) (newrelic.Application, error) {
    58  	cfg := newrelic.NewConfig(name, mustGetEnv("NEW_RELIC_LICENSE_KEY"))
    59  	cfg.Logger = newrelic.NewDebugLogger(os.Stdout)
    60  
    61  	// Distributed Tracing and Cross Application Tracing cannot both be
    62  	// enabled at the same time.
    63  	cfg.DistributedTracer.Enabled = true
    64  
    65  	app, err := newrelic.NewApplication(cfg)
    66  
    67  	if nil != err {
    68  		return nil, err
    69  	}
    70  
    71  	// Wait for the application to connect.
    72  	if err = app.WaitForConnection(5 * time.Second); nil != err {
    73  		return nil, err
    74  	}
    75  
    76  	return app, nil
    77  }
    78  
    79  func main() {
    80  	// Calling processes have no command line arguments, called processes
    81  	// have one command line argument (the payload).
    82  	isCalled := (len(os.Args) > 1)
    83  
    84  	// Initialize the application name.
    85  	name := "Go Custom Instrumentation"
    86  	if isCalled {
    87  		name += " Called"
    88  	} else {
    89  		name += " Calling"
    90  	}
    91  
    92  	// Initialize the application.
    93  	app, err := makeApplication(name)
    94  	if nil != err {
    95  		fmt.Println(err)
    96  		os.Exit(1)
    97  	}
    98  
    99  	// Run calling/called routines.
   100  	if isCalled {
   101  		payload := os.Args[1]
   102  		called(app, payload)
   103  	} else {
   104  		calling(app)
   105  	}
   106  
   107  	// Shut down the application to flush data to New Relic.
   108  	app.Shutdown(10 * time.Second)
   109  }