Log streaming: New Relic OTLP

Fastly's Real-Time Log Streaming feature can send log files to New Relic OTLP.

NOTE

Fastly does not provide direct support for third-party services. Read Fastly's Terms of Service for more information.

Prerequisites

Before adding New Relic OTLP as a logging endpoint for Fastly services, you will need to:

Adding New Relic OTLP as a logging endpoint

Follow these instructions to add New Relic OTLP as a logging endpoint:

  1. Deliver services
  2. Compute services
  1. Review the information in our guide to setting up remote log streaming.
  2. In the New Relic OTLP area, click Create endpoint.
  3. Fill out the Create a New Relic OTLP endpoint fields as follows:
    • In the Name field, enter a human-readable name for the endpoint.
    • In the License key / Insert key field, enter your New Relic license key or Insert API key.
    • From the Region controls, select the region to stream logs to.
  4. (Optional) If you are using New Relic Infinite Tracing, click Advanced options and enter your New Relic Trace Observer URL in the Trace Observer URL field.
  5. Click Create to create the new logging endpoint.
  6. Click Activate to deploy your configuration changes.
  7. Follow the instructions below to instrument your VCL service.

Instrumenting your VCL service

After setting up your endpoint, you will need to add custom VCL to gather the data and generate Open Telemetry traces at the edge.

  1. Place the following functions at the top of your custom VCL file.

    1sub time_now_ns STRING {
    2 declare local var.time_now INTEGER;
    3 set var.time_now = std.atoi(time.start.usec);
    4 set var.time_now += std.atoi(time.elapsed.usec);
    5 set var.time_now *= 1000;
    6 return var.time_now;
    7}
    8sub random_8bit_identifier STRING {
    9 declare local var.id STRING;
    10 set var.id = randomstr(16, "0123456789abcdef");
    11 return var.id;
    12}
    13sub random_16bit_identifier STRING {
    14 declare local var.id STRING;
    15 set var.id = randomstr(32, "0123456789abcdef");
    16 return var.id;
    17}
    18
    19sub otel_resource STRING {
    20 declare local var.str STRING;
    21 set var.str = {"{ "attributes": [ "}
    22 {"{ "key": "service.name", "value": { "stringValue": "Fastly www" } }, "}
    23 {"{ "key": "telemetry.sdk.language", "value": { "stringValue": "vcl" } }, "}
    24 {"{ "key": "telemetry.sdk.name", "value": { "stringValue": "opentelemetry" } }, "}
    25 {"{ "key": "telemetry.sdk.version", "value": { "stringValue": "1.0.1" } }, "}
    26 {"{ "key": "host.name", "value": { "stringValue": ""} server.identity {"" } }"}
    27 {"], "droppedAttributesCount": 0 }"};
    28 return var.str;
    29}
    30
    31sub otel_attributes_general STRING {
    32 declare local var.data STRING;
    33 set var.data = ""
    34 {"{ "key": "http.method", "value": { "stringValue": ""} req.method {"" } },"}
    35 {"{ "key": "http.target", "value": { "stringValue": ""} req.url {"" } },"}
    36 {"{ "key": "http.host", "value": { "stringValue": ""} req.http.host {"" } },"}
    37 {"{ "key": "http.protocol", "value": { "stringValue": ""} req.protocol {"" } },"}
    38 {"{ "key": "http.client_ip", "value": { "stringValue": ""} client.ip {"" } },"}
    39
    40 {"{ "key": "fastly.restarts", "value": { "stringValue": ""} req.restarts {"" } },"}
    41 {"{ "key": "fastly.visits_this_service", "value": { "stringValue": ""} fastly.ff.visits_this_service {"" } },"}
    42 {"{ "key": "fastly.server_role", "value": { "stringValue": ""} req.http.x-trace-server-role {"" } },"}
    43 {"{ "key": "fastly.server_ip", "value": { "stringValue": ""} server.ip {"" } },"}
    44 {"{ "key": "fastly.server_id", "value": { "stringValue": ""} server.identity {"" } },"}
    45 {"{ "key": "fastly.server_role", "value": { "stringValue": ""} req.http.x-trace-server-role {"" } },"}
    46 {"{ "key": "fastly.vcl_version", "value": { "stringValue": ""} req.vcl.version {"" } },"}
    47 {"{ "key": "fastly.pop", "value": { "stringValue": ""} server.datacenter {"" } },"}
    48 {"{ "key": "fastly.workspace.overflowed", "value": { "stringValue": ""} workspace.overflowed {"" } },"}
    49 {"{ "key": "fastly.workspace.bytes_total", "value": { "stringValue": ""} workspace.bytes_total {"" } },"}
    50 {"{ "key": "fastly.workspace.bytes_free", "value": { "stringValue": ""} workspace.bytes_free {"" } },"}
    51 ;
    52 return var.data;
    53}
    54
    55sub telem_start_backend_fetch {
    56 set bereq.http.traceparent = "00-" req.http.x-trace-id + "-" + req.http.x-trace-vcl-span-id "-01";
    57
    58 # Avoid leaking internal headers to backends
    59 unset bereq.http.x-trace-id;
    60 unset bereq.http.x-trace-parent-span-id;
    61 unset bereq.http.x-trace-server-role;
    62
    63 # Leapfrog cloud service infra that creates 'ghost spans'
    64 set bereq.http.x-traceparent = bereq.http.traceparent;
    65}
  2. Add the following VCL to the start of the vcl_recv subroutine to record a span for the whole of a request's lifetime within a Fastly POP.

    1if (req.restarts == 0) {
    2 set req.http.x-trace-vcl-span-id = random_8bit_identifier();
    3 if (req.http.traceparent ~ "^\d+-(\w+)-(\w+)-\d+$") {
    4 set req.http.x-trace-id = re.group.1;
    5 set req.http.x-trace-parent-span-id = re.group.2;
    6 } else {
    7 set req.http.x-trace-id = random_16bit_identifier();
    8 }
    9 set req.http.x-trace-server-role = if (fastly.ff.visits_this_service == 0, "edge", "shield");
    10}
  3. Add the following VCL to the end of the vcl_log subroutine, replacing otel_collector_http with the name of your endpoint.

    1declare local var.otel_resource STRING;
    2declare local var.otel_attribs STRING;
    3declare local var.time_start_ns STRING;
    4declare local var.time_now_ns STRING;
    5set var.time_start_ns = time.start.usec "000";
    6set var.time_now_ns = time_now_ns();
    7set var.otel_resource = otel_resource();
    8set var.otel_attribs = otel_attributes_general();
    9log "syslog " req.service_id " otel_collector_http :: "
    10 {"{ "resourceSpans": [ { "}
    11 {""resource": "} var.otel_resource {", "}
    12 {""instrumentationLibrarySpans": [ { "spans": [ { "}
    13 {""traceId": ""} req.http.x-trace-id {"", "}
    14 {""spanId": ""} req.http.x-trace-vcl-span-id {"", "}
    15 if(req.http.x-trace-parent-span-id,
    16 {""parentSpanId": ""} req.http.x-trace-parent-span-id {"", "},
    17 "")
    18 {""name": "Fastly request processing", "}
    19 {""kind": 1, "}
    20 {""startTimeUnixNano": "} var.time_start_ns {", "}
    21 {""endTimeUnixNano": "} var.time_now_ns {", "}
    22 {""attributes": [ "}
    23 var.otel_attribs
    24 {"{ "key": "http.user_agent", "value": { "stringValue": ""} req.http.User-Agent {"" } }, "}
    25 {"{ "key": "http.status_code", "value": { "stringValue": ""} resp.status {"" } }"}
    26 {"], "}
    27 {""status": { "code":"} if (fastly_info.state ~ "ERROR", "2", "0") {" }, "}
    28 {""links": [], "}
    29 {""droppedLinksCount": 0"}
    30 {"} ] } ]"}
    31 {"} ] }"}
    32;
  4. Add a call to telem_start_backend_fetch and place it in the vcl_miss and vcl_pass subroutines to see spans that happen in backend systems as children of the Fastly spans.

  5. Activate the service.

Was this guide helpful?

Do not use this form to send sensitive information. If you need assistance, contact support. This form is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.