Want to Contribute to us or want to have 15k+ Audience read your Article ? Or Just want to make a strong Backlink?

The Power of Traces: Learn by Contributing to OpenTelemetry

Right this moment you’ll learn to contribute to the OpenTelemetry Demo repo safely, by studying to put in writing OpenTelemetry code instrumentation and testing your contributions by writing trace-based checks.

I additionally wish to present a complete understanding of OpenTelemetry, and demystify utilizing it to assist the group make significant contributions to the OpenTelemetry undertaking.

These are the 4 questions you’ll know the way to reply by the tip of this tutorial.

  1. What’s Observability?
  2. What’s OpenTelemetry?
  3. What’s the OpenTelemetry Demo repo?
  4. Easy methods to contribute to the OpenTelemetry Demo repo?
  5. What’s trace-based testing and the way do you run trace-based checks?

I’ll present explanations for every of those questions and clarify the challenges confronted by maintainers when merging pull requests, typically resulting in damaged options and telemetry.

Let’s soar in!

You can even watch this dwell stream on this subject here.



What’s Observability?

Observability refers back to the means to realize insights into the interior state and conduct of a system via its outputs. Within the context of OpenTelemetry, observability focuses on distributed tracing, which lets you hint requests as they stream via a system and perceive the interactions between varied elements.

To be taught extra about observability and distributed tracing, check with the OpenTelemetry observability primer.



Understanding Distributed Tracing

A distributed hint has 4 elements:

  1. The hint
  2. Spans representing every step
  3. Attributes related to every span
  4. Occasions related to every span

A hint consists of a number of spans, with the preliminary span as the foundation, representing the complete request journey. Subsequent spans present an in depth context of the steps in a request.

A distributed hint, or just a hint, traces the trail of a request in multi-service architectures like microservices and serverless apps.

With out tracing, pinpointing efficiency points in a distributed system is difficult. Tracing enhances visibility in functions, making debugging elusive points straightforward.

It simplifies the daunting process of debugging and understanding advanced distributed programs by breaking down the sequence of occasions inside a request.



What’s OpenTelemetry?

OpenTelemetry is a strong observability framework that allows the gathering, evaluation, and export of telemetry information from functions. It supplies a standardized method for instrumenting code, permitting builders to realize priceless insights into software efficiency and conduct. With OpenTelemetry, monitoring and troubleshooting programs, figuring out bottlenecks, and optimizing software efficiency turns into simpler.



Demystifying OpenTelemetry

Let’s demystify OpenTelemetry collectively and embark on a journey of energetic contribution to the OpenTelemetry Demo. By doing so, we will collectively advance the state of observability and empower builders worldwide to construct extra dependable and performant functions.



Understanding Code Instrumentation

OpenTelemetry code instrumentation is out there for a variety of widespread programming languages.

OpenTelemetry code instrumentation is supported for 11+ languages. The matters lined might fluctuate relying on the language and may embody the next:

In case you are utilizing Kubernetes, you should utilize the OpenTelemetry Operator for Kubernetes to routinely inject instrumentation libraries for .NET, Java, Node.js, Python, and Go into your software.



Including OpenTelemetry Automated Instrumentation

That is the magical auto instrumentation function, which lets you generate traces with out making any code adjustments. Additional down within the tutorial I’ll exhibit how auto instrumentation works in Node.js utilizing the paymentservice from the OpenTelemetry Demo, which is conveniently written in Node.js.

The paymentservice is a part of the OpenTelemetry Demo. Let me transfer on and clarify what the OpenTelemetry Demo is and why it exists.



What’s the OpenTelemetry Demo?

In April 2021, the OpenTelemetry Venture created a demo app as an example the way to instrument a various distributed system.

The undertaking is broadly widespread, with 1.1k stars and 500 forks on GitHub. It has 89 contributors from world wide, and within the final month alone, 9 builders merged 32 pull requests into the repository.

https://res.cloudinary.com/djwdcmwdz/image/upload/v1700047097/Blogposts/blogpost-from-cnl-live/Screenshot_2023-11-15_at_11.42.05_gq1eed.png

Contributing to the OpenTelemetry Demo is a good way to get entangled and showcase your abilities within the OpenTelemetry group. It is a real-world instance of OpenTelemetry in motion, and by actively contributing, you improve your understanding and enhance the undertaking’s high quality.

The microservice app, centered across the observability theme of the OTel undertaking, is an Astronomy Retailer Entrance, supporting 11 languages and 12 services with each computerized and handbook instrumentation.

https://res.cloudinary.com/djwdcmwdz/image/upload/v1700047125/Blogposts/blogpost-from-cnl-live/image_59_hxebnw.png

The OpenTelemetry Demo consists of microservices written in numerous programming languages that discuss to one another over gRPC and HTTP; and a load generator which makes use of Locust to pretend person site visitors.

https://res.cloudinary.com/djwdcmwdz/image/upload/v1700047157/Blogposts/blogpost-from-cnl-live/Screenshot_2023-11-08_at_14.48.46_gl6rxw.png

You’re questioning, why all of the complexity? Effectively, you wish to mimic actual life as carefully as attainable. That’s what you get! Having to handle such a distributed system makes it arduous to reliably merge new options. There are 4 essential ache factors.

  • It’s straightforward to introduce regressions.
  • It’s straightforward to interrupt telemetry.
  • It’s straightforward to interrupt service-to-service communication.
  • It’s arduous to check.

Now, after you have a transparent understanding of what the OpenTelemetry Demo is, let me transfer on and clarify how one can contribute by operating all providers, enhancing code and including trace-based checks!



Contributing to the OpenTelemetry Demo

You may set up and run the OpenTelemetry Demo in Docker with these commands:

git clone https://github.com/open-telemetry/opentelemetry-demo.git
cd opentelemetry-demo/
make begin
Enter fullscreen mode

Exit fullscreen mode

💡 Notice: In the event you’re operating on Apple Silicon, run make construct with a view to create native photos vs. pulling them from the repository.

Let’s begin with the docker-compose.yml. It accommodates 4 varieties of providers.

  • Core Demo Companies
  • Dependent Companies
  • Telemetry Parts
  • Checks



Core Demo Companies

These are the core providers that make up the demo itself. The buying cart, the entrance finish, adverts, accounting, and far more. It’s the entire function set of the “Astronomy Store” web site!



Dependent Companies

These providers are required and utilized by the Core Demo Companies. They embody Postgres, Kafka, and Redis.



Telemetry Parts

These providers are solely targeted on observability. Which means, gathering, storing, and visualizing telemetry information. They embody Jaeger, Grafana, OpenSearch, Prometheus, and OpenTelemetry Collector.



Checks

The take a look at providers cowl front-end, integration, and trace-based checks. Together with the Tracetest Server that runs the trace-based checks.



Docker Compose Companies Match the Structure

Because the docker-compose.yml file is just too massive to embed in its entirety inside an internet web page, I’ve linked it here for you to check out.

Trying on the docker-compose.yml you too can see the sections match the structure overview from above.

One other cool factor to notice within the docker-compose.yml is the checks profile.

Profiles (in Docker Compose) enable you to alter the Compose software mannequin for varied makes use of and environments by selectively beginning providers. That is achieved by assigning every service to zero or extra profiles. If unassigned, the service is all the time began but when assigned, it’s only began if the profile is activated.
Docker Compose Website

That is handy as a result of you can begin all providers excluding the checks by operating this command.

docker compose up
Enter fullscreen mode

Exit fullscreen mode

However, if you wish to embody the checks, then including a --profile flag will begin them as nicely.

docker compose --profile checks up
Enter fullscreen mode

Exit fullscreen mode

Lastly, if you wish to allow API observability-driven testing, you employ one other profile referred to as odd.

docker compose --profile odd up
Enter fullscreen mode

Exit fullscreen mode



Use the Makefile

The makefile accommodates all of the shorthand instructions to construct, run, and take a look at the OpenTelemetry Demo.

To begin it, you run:

make begin
Enter fullscreen mode

Exit fullscreen mode

Then you might have extra instructions to cease it, construct the pictures, and run checks.

make cease
make construct
make run-tests
Enter fullscreen mode

Exit fullscreen mode

To run the trace-based checks alone, you may run this command.

make run-tracetesting
Enter fullscreen mode

Exit fullscreen mode

This command will begin solely the traceBasedTests Docker Compose service. Basically, it’ll run:

docker compose run traceBasedTests ${SERVICES_TO_TEST}
Enter fullscreen mode

Exit fullscreen mode

The place the ${SERVICES_TO_TEST} is a parameter you may go to outline which particular providers to run checks in opposition to. Within the docker-compose.yml you may see precisely what Dockerfile the traceBasedTests service makes use of.

  # [...]
    traceBasedTests:
    picture: ${IMAGE_NAME}:${IMAGE_VERSION}-traceBasedTests
    container_name: traceBasedTests
    profiles:
      - checks
    construct:
      context: ./
      dockerfile: ./take a look at/tracetesting/Dockerfile
  # [...]
Enter fullscreen mode

Exit fullscreen mode

The Dockerfile within the take a look at/tracetesting folder installs the Tracetest CLI to run checks, and executes a Bash file referred to as run.bash.

# Dockerfile

# Copyright The OpenTelemetry Authors
# SPDX-License-Identifier: Apache-2.0

FROM alpine

WORKDIR /app

RUN apk --update add bash jq curl
RUN curl -L https://uncooked.githubusercontent.com/kubeshop/tracetest/essential/install-cli.sh | bash -s -- ${TRACETEST_IMAGE_VERSION}

WORKDIR /app/take a look at/tracetesting

ENTRYPOINT ["/bin/bash", "/app/test/tracetesting/run.bash"]
Enter fullscreen mode

Exit fullscreen mode

The run.bash file will dynamically both run checks in opposition to all providers or simply those you go as parameters. It can additionally generate an env file for Tracetest to know the way to attain the completely different providers with a view to take a look at them. It grabs the values from the .env file from the root of the repository.

With that, you’re able to run your first checks. Begin by solely operating the paymentservice checks.

docker compose run traceBasedTests "payment-service"

# OR

make run-tracetesting SERVICES_TO_TEST="payment-service"
Enter fullscreen mode

Exit fullscreen mode

After a couple of minutes you’ll see this in your terminal.

make run-tracetesting SERVICES_TO_TEST="payment-service"

[ Output ]
docker compose run traceBasedTests payment-service
[+] Creating 21/0
 ✔ Container jaeger                   Operating                                                                                                                            0.0s
 ✔ Container kafka                    Operating                                                                                                                            0.0s
 ✔ Container tracetest-postgres       Operating                                                                                                                            0.0s
 ✔ Container postgres                 Operating                                                                                                                            0.0s
 ✔ Container redis-cart               Operating                                                                                                                            0.0s
 ✔ Container feature-flag-service     Operating                                                                                                                            0.0s
 ✔ Container otel-col                 Operating                                                                                                                            0.0s
 ✔ Container currency-service         Operating                                                                                                                            0.0s
 ✔ Container cart-service             Operating                                                                                                                            0.0s
 ✔ Container payment-service          Operating                                                                                                                            0.0s
 ✔ Container tracetest-server         Operating                                                                                                                            0.0s
 ✔ Container quote-service            Operating                                                                                                                            0.0s
 ✔ Container accounting-service       Operating                                                                                                                            0.0s
 ✔ Container frauddetection-service   Operating                                                                                                                            0.0s
 ✔ Container product-catalog-service  Operating                                                                                                                            0.0s
 ✔ Container ad-service               Operating                                                                                                                            0.0s
 ✔ Container email-service            Operating                                                                                                                            0.0s
 ✔ Container recommendation-service   Operating                                                                                                                            0.0s
 ✔ Container shipping-service         Operating                                                                                                                            0.0s
 ✔ Container checkout-service         Operating                                                                                                                            0.0s
 ✔ Container frontend                 Operating                                                                                                                            0.0s
[+] Operating 3/3
 ✔ Container postgres            Wholesome                                                                                                                                 0.5s
 ✔ Container kafka               Wholesome                                                                                                                                 0.5s
 ✔ Container tracetest-postgres  Wholesome                                                                                                                                 0.5s
Beginning checks...

Operating trace-based checks...

✔ Fee Service (http://tracetest-server:11633/testsuite/payment-service-all/run/2)
    ✔ Fee: legitimate bank card (http://tracetest-server:11633/take a look at/payment-valid-credit-card/run/2/take a look at) - hint id: 7774d4754957e5fa5b916e4d6d5880e7
        ✔ It ought to name Cost methodology efficiently
        ✔ It ought to return a transaction ID
        ✔ It ought to return a legitimate bank card
    ✔ Fee: invalid bank card (http://tracetest-server:11633/take a look at/payment-invalid-credit-card/run/2/take a look at) - hint id: a20c1d166cd6edf4d8f288e407e76623
        ✔ It ought to name Cost methodology and obtain a gRPC error
        ✔ It ought to return a return an gRPC error code to the caller
    ✔ Fee: Amex bank card not allowed (http://tracetest-server:11633/take a look at/payment-amex-credit-card-not-allowed/run/2/take a look at) - hint id: a5812bf50ac61a387dc991ba0dd3020a
        ✔ It ought to name Cost methodology and obtain a gRPC error
        ✔ It ought to return a return an gRPC error code to the caller
    ✔ Fee: expired bank card (http://tracetest-server:11633/take a look at/payment-expired-credit-card/run/2/take a look at) - hint id: fecb6368104b0fc27e7806136fc1ab1c
        ✔ It ought to name Cost methodology and obtain a gRPC error
        ✔ It ought to return a return an gRPC error code to the caller

Checks executed! Exit code: 0
Enter fullscreen mode

Exit fullscreen mode

You can even begin the Tracetest providers alongside all of the Core Demo Companies, Dependent Companies, and Telemetry Parts as a part of your growth lifecycle to allow Observability-driven Development (ODD). Primarily to set off your APIs and validate each the response and hint information they generate. You can even construct checks visually and save them as YAML information so as to add to your code repo for automated testing. I’ll stroll you thru all of this a bit later as nicely.

To do that, you’ll use the odd Docker Compose profile. Run the demo like this:

docker compose --profile odd up --force-recreate --remove-orphans --detach

# OR

make start-odd
Enter fullscreen mode

Exit fullscreen mode

Go forward and begin the OpenTelemetry Demo together with Tracetest, with the odd profile.

As soon as the pictures are constructed and containers are began you may entry:

To run a take a look at in opposition to the Fee Service, I’ll use a YAML file and set off it with the Tracetest CLI. Alternatively, you too can construct checks visually within the Tracetest UI on http://localhost:11633/.

Right here’s a short guide on how to create tests programatically with Tracetest.

Subsequent, let’s transfer on to explaining and including code instrumentation within the paymentservice.



Including OpenTelemetry to the Fee Service

I’ve ready a fork with detailed code examples and three demos. It will enable you to perceive the way to add OpenTelemetry code instrumentation.

git clone https://github.com/kubeshop/opentelemetry-demo.git
cd opentelemetry-demo/
make start-odd
Enter fullscreen mode

Exit fullscreen mode

Right here’s a snippet of what configuring automatic instrumentation for Node.js looks like in the src/paymentservice/opentelemetry.js file.

// src/paymentservice/opentelemetry.js

const opentelemetry = require("@opentelemetry/sdk-node")
const {getNodeAutoInstrumentations} = require("@opentelemetry/auto-instrumentations-node")
const {OTLPTraceExporter} = require('@opentelemetry/exporter-trace-otlp-grpc')
const {OTLPMetricExporter} = require('@opentelemetry/exporter-metrics-otlp-grpc')
const {PeriodicExportingMetricReader} = require('@opentelemetry/sdk-metrics')
const {alibabaCloudEcsDetector} = require('@opentelemetry/resource-detector-alibaba-cloud')
const {awsEc2Detector, awsEksDetector} = require('@opentelemetry/resource-detector-aws')
const {containerDetector} = require('@opentelemetry/resource-detector-container')
const {gcpDetector} = require('@opentelemetry/resource-detector-gcp')
const {envDetector, hostDetector, osDetector, processDetector} = require('@opentelemetry/sources')

const sdk = new opentelemetry.NodeSDK({
  // OTLPTraceExporter() makes use of the env var "OTEL_EXPORTER_OTLP_ENDPOINT" when not explicitly set.
  traceExporter: new OTLPTraceExporter(),
  instrumentations: [
    getNodeAutoInstrumentations()
  ],
  metricReader: new PeriodicExportingMetricReader({
    exporter: new OTLPMetricExporter(),
  }),
  resourceDetectors: [
    containerDetector,
    envDetector,
    hostDetector,
    osDetector,
    processDetector,
    alibabaCloudEcsDetector,
    awsEksDetector,
    awsEc2Detector,
    gcpDetector
  ],
})
sdk.begin()
Enter fullscreen mode

Exit fullscreen mode

View computerized instrumentation samples for different programming languages, here.

These few strains of code will routinely begin producing hint spans to your service.

The paymentservice additionally contains manually instrumented spans as nicely. In the event you check out the src/paymentservice/index.js and src/paymentservice/charge.js you’ll see a require assertion for the @opentelemetry/api, and a tracer that creates a span with some attributes.

// src/paymentservice/index.js

// Line 6
const { hint, context, SpanStatusCode } = require('@opentelemetry/api')
const tracer = hint.getTracer('paymentservice')

// [...]

perform chargeServiceHandler(name, callback) {

    // Line 23
  const span = hint.getActiveSpan()
    strive {
        const quantity = name.request.quantity

      span.setAttributes({
        'app.cost.quantity': parseFloat(`${quantity.items}.${quantity.nanos}`)
      })
      span.addEvent('Cost request acquired.', {
        'log.severity': 'information',
        'log.message': 'Cost request acquired.',
        'request': name.request,
      })

      const response = cost.cost(name.request)

      // [...]
    } catch (err) {
        // [...]
    }
}

// src/paymentservice/cost.js
// Line 4
const opentelemetry = require('@opentelemetry/api')
const {context, propagation, hint, metrics} = opentelemetry
// [...]
// Line 10
const tracer = hint.getTracer('paymentservice')
// [...]
// Line 21
const span = hint.getActiveSpan()
// [...]
// Line 53
span.setAttributes({
  'app.cost.card_type': cardType,
  'app.cost.card_valid': legitimate
})
// [...]
Enter fullscreen mode

Exit fullscreen mode

I’ll stroll you thru these three demos, with one pattern with out telemetry.

  1. Demo 0: What’s it like with out OpenTelemetry traces?
  2. Demo 1: Get the energetic span from the context and use it as the primary span within the chargeServiceHandler .
  3. Demo 2: Get the energetic span from the context to create a brand new context. Create a brand new span for the chargeServiceHandler and go the brand new context in as a parameter.
  4. Demo 3: Create a brand new energetic span for the chargeServiceHandler with out the necessity to go a guardian span and context.

However first, let’s make it tougher! It’s straightforward to get began when anyone is holding your hand. Let’s take away the guardrails for a second. Actually, let’s take away the OpenTelemetry instrumentation and run some API checks to see what occurs.



Eradicating OpenTelemetry and Operating API Checks

With out the opentelemetry.js file that accommodates auto instrumentation, triggering the paymentservice/cost API endpoint will lead to no traces exhibiting up. Let’s reproduce this by operating an API take a look at with Tracetest. First, I’ll remark out all of the content material within the opentelemetry.js file. Then, remark out all of the OpenTelemetry-specific code within the index.js and cost.js.

You’ll see a “0. Demo” remark part. In the event you need assistance determining what code to exclude, it may be your guideline.

// src/paymentservice/index.js

perform chargeServiceHandler(name, callback) {
  /**
   * 0. Demo Begin
   * 0. Demo: No telemetry
   */
  strive {
    const response = cost.cost(name.request)
    callback(null, response)
  } catch (err) {
    callback(err)
  }
  /**
   * 0. Demo Finish
   */
}

// src/paymentservice/cost.js

// Remark out code under this block remark:
/**
 * 1. & 2. & 3. Demo
 * Finish the span.
 */
Enter fullscreen mode

Exit fullscreen mode

To run a take a look at in opposition to the Fee Service, I’ll use a YAML file and set off it with the Tracetest CLI.

The take a look at is positioned within the take a look at/tracetesting/payment-service/cnl-demo listing. The listing has a single file referred to as exploratory-test.yaml.

# exploratory-test.yaml

kind: Check
spec:
  id: payment-valid-credit-card
  identify: "Fee: Exploratory take a look at of credit score card"
  description: Cost buyer with a bank card
  set off:
    kind: grpc
    grpc:
      protobufFile: ../../../../pb/demo.proto
      deal with: paymentservice:50051
      methodology: oteldemo.PaymentService.Cost
      request: |-
        {
          "quantity": {
            "currencyCode": "USD",
            "items": 43,
            "nanos": 130000000
          },
          "creditCard": {
            "creditCardNumber": "4432-8015-6152-0454",
            "creditCardCvv": 672,
            "creditCardExpirationYear": 2039,
            "creditCardExpirationMonth": 1
          }
        }
Enter fullscreen mode

Exit fullscreen mode

As you see it’s a gRPC API and it’s utilizing a protobuf file called demo.proto. Right here’s a snippet for the Cost methodology within the demo.proto.

// Line 179
service PaymentService {
    rpc Cost(ChargeRequest) returns (ChargeResponse) {}
}

message CreditCardInfo {
    string credit_card_number = 1;
    int32 credit_card_cvv = 2;
    int32 credit_card_expiration_year = 3;
    int32 credit_card_expiration_month = 4;
}

message ChargeRequest {
    Cash quantity = 1;
    CreditCardInfo credit_card = 2;
}

message ChargeResponse {
    string transaction_id = 1;
}
Enter fullscreen mode

Exit fullscreen mode

Triggering the take a look at is as straightforward as operating this command with the Tracetest CLI.

tracetest run take a look at -f path-to-dir/exploratory-test.yaml
Enter fullscreen mode

Exit fullscreen mode

https://res.cloudinary.com/djwdcmwdz/image/upload/v1699480569/Blogposts/blogpost-from-cnl-live/screely-1699480563460_dszbz6.png

The take a look at will return a response simply effective, however the hint polling will timeout because it gained’t have the ability to discover any traces.

https://res.cloudinary.com/djwdcmwdz/image/upload/v1699480657/Blogposts/blogpost-from-cnl-live/screely-1699480651270_jl1o1y.png

It is smart because you simply disabled the OpenTelemetry code instrumentation.



Studying About Energetic Spans and Context

Let me backtrack and add each the automated and handbook instrumentation again into the paymentservice. As soon as I add them and set off the paymentservice/cost API endpoint, traces can be displayed and I’ll have the ability to create checks. It’s so simple as that to get began!

As I discussed above, I’ve ready feedback labeled “1. Demo” that showcase which commented code to incorporate. This demo reveals the way to use the energetic rpc span from the injected gRPC instrumentation as the primary span within the chargeServiceHandler . All our further handbook telemetry can be added to that span.

Open up the src/paymentservice/index.js and src/paymentservice/charge.js as soon as once more.

Be sure that to incorporate these strains:

// src/paymentservice/index.js

// [...]
const { hint, context, SpanStatusCode } = require('@opentelemetry/api')
// [...]
perform chargeServiceHandler(name, callback) {
    const span = hint.getActiveSpan()
    strive {
    const quantity = name.request.quantity

    /**
     * Add span attributes and occasions for customized take a look at specs
     */
    span.setAttributes({
      'app.cost.quantity': parseFloat(`${quantity.items}.${quantity.nanos}`)
    })
    span.addEvent('Cost request acquired.', {
      'log.severity': 'information',
      'log.message': 'Cost request acquired.',
      'request': name.request,
    })

    const response = cost.cost(name.request)

    /**
     * Add span attributes and occasions for customized take a look at specs
     */
    span.setStatus({ code: SpanStatusCode.OK })
    span.finish()

    callback(null, response)

  } catch (err) {

    /**
     * Add span attributes and occasions for customized take a look at specs
     */
    span.addEvent('Cost request error.', {
      'log.severity': 'warn',
      'log.message': 'Cost request error.',
      'error': err,
    })
    span.recordException(err)
    span.setStatus({ code: SpanStatusCode.ERROR })
    span.finish()

    callback(err)
  }
}

// src/paymentservice/cost.js

const opentelemetry = require('@opentelemetry/api')
const {context, propagation, hint, metrics} = opentelemetry
// [...]
module.exports.cost = request => {
    const span = hint.getActiveSpan()

    const {
    creditCardNumber: quantity,
    creditCardExpirationYear: 12 months,
    creditCardExpirationMonth: month
  } = request.creditCard
  const currentMonth = new Date().getMonth() + 1
  const currentYear = new Date().getFullYear()
  const lastFourDigits = quantity.substr(-4)
  const transactionId = uuidv4()

  const card = cardValidator(quantity)
  const { card_type: cardType, legitimate } = card.getCardDetails()

  span.setAttributes({
    'app.cost.card_type': cardType,
    'app.cost.card_valid': legitimate
  })

  if (!legitimate) {
    throw new Error('Bank card information is invalid.')
  }

  if (!['visa', 'mastercard'].contains(cardType)) {
    throw new Error(`Sorry, we can not course of ${cardType} bank cards. Solely VISA or MasterCard is accepted.`)
  }

  if ((currentYear * 12 + currentMonth) > (12 months * 12 + month)) {
    throw new Error(`The bank card (ending ${lastFourDigits}) expired on ${month}/${12 months}.`)
  }

  const baggage = propagation.getBaggage(context.energetic())
  if (baggage && baggage.getEntry("synthetic_request") && baggage.getEntry("synthetic_request").worth === "true") {
    span.setAttribute('app.cost.charged', false)
  } else {
    span.setAttribute('app.cost.charged', true)
  }

  span.finish()

  const { items, nanos, currencyCode } = request.quantity
  // [...]
  transactionsCounter.add(1, {"app.cost.forex": currencyCode})
  return { transactionId }
}
Enter fullscreen mode

Exit fullscreen mode

Operating the take a look at once more will present the rpc span accurately.

tracetest run take a look at -f path-to-dir/exploratory-test.yaml
Enter fullscreen mode

Exit fullscreen mode

https://res.cloudinary.com/djwdcmwdz/image/upload/v1700047242/Blogposts/blogpost-from-cnl-live/screely-1700047234012_bxdjw9.png

Nonetheless, you’re nonetheless not there but! I need you to know the way to create a toddler span under the rpc span. The kid span can be devoted too the cost.js file and make it simpler to view span attributes individually as a substitute of bundling all of them onto one span.



Studying to Add a Youngster Span

Let’s return to the src/paymentservice/index.js and src/paymentservice/charge.js.

Edit the information to make use of the “2. Demo”. You solely want to vary the actual strains I’ll present under. The remainder of the file can keep the identical.

// src/paymentservice/index.js

// [...]
perform chargeServiceHandler(name, callback) {
  // [...]
  const guardian = hint.getActiveSpan()
  const ctx = hint.setSpan(context.energetic(), guardian)
  const span = tracer.startSpan('chargeServiceHandler', undefined, ctx)
  // [...]
}

// src/paymentservice/cost.js

module.exports.cost = request => {
  // [...]
  const guardian = hint.getActiveSpan()
  const ctx = hint.setSpan(context.energetic(), guardian)
  const span = tracer.startSpan('cost', undefined, ctx)
  // [...]
}
Enter fullscreen mode

Exit fullscreen mode

What occurs now?

With this tradition instrumentation added to the Fee Service’s index.js and cost.js information, you’ll add two youngster spans to the rpc guardian span.

Set off the exploratory trace-based take a look at as soon as once more to see what it seems to be like.

tracetest run take a look at -f path-to-dir/exploratory-test.yaml
Enter fullscreen mode

Exit fullscreen mode

https://res.cloudinary.com/djwdcmwdz/image/upload/v1700047281/Blogposts/blogpost-from-cnl-live/screely-1700047275837_u99cxs.png

Now, add an assertion to validate the cardboard is legitimate. You do that by choosing the app.cost.card_valid span and clicking “Create take a look at spec”, and continuing so as to add it visually.

https://res.cloudinary.com/djwdcmwdz/image/upload/v1700047315/Blogposts/blogpost-from-cnl-live/screely-1700047309629_fkkhu6.png

Or, add the assertion programatically to the take a look at definition YAML file.

specs:
  - identify: It must be a legitimate card
    selector: span[tracetest.span.type="general" name="charge"]
    assertions:
    - attr:app.cost.card_valid = "true"
Enter fullscreen mode

Exit fullscreen mode

See this file for reference.



Including an Energetic Span and a Youngster Span

Taking it a step additional, let me stroll you thru including an energetic span and attaching the cost span as a toddler span onto it. It will clear up your distributed hint and create a pleasant hierarchy.

Let’s return to the src/paymentservice/index.js and src/paymentservice/charge.js one final time.

Edit the information to make use of the “3. Demo”. You solely want to vary the actual strains I’ll present under. The remainder of the file can keep the identical.

// src/paymentservice/index.js

// [...]
perform chargeServiceHandler(name, callback) {
  // [...]
  return tracer.startActiveSpan('chargeServiceHandler', span => {
    strive {
      const quantity = name.request.quantity

      span.setAttributes({
        'app.cost.quantity': parseFloat(`${quantity.items}.${quantity.nanos}`)
      })
      span.addEvent('Cost request acquired.', {
        'log.severity': 'information',
        'log.message': 'Cost request acquired.',
        'request': name.request,
      })

      const response = cost.cost(name.request)

      span.setStatus({ code: SpanStatusCode.OK })
      span.finish()

      callback(null, response)

    } catch (err) {

      span.addEvent('Cost request error.', {
        'log.severity': 'warn',
        'log.message': 'Cost request error.',
        'error': err,
      })
      span.recordException(err)
      span.setStatus({ code: SpanStatusCode.ERROR })
      span.finish()

      callback(err)
    }
  })
  // [...]
}

// src/paymentservice/cost.js

module.exports.cost = request => {
  // [...]
  const span = tracer.startSpan('cost')
  // [...]
}
Enter fullscreen mode

Exit fullscreen mode

There are two essential issues to recollect and take away from this third demo.

  • The startActiveSpan() methodology returns a Promise.
  • Each span created with the startSpan() methodology throughout the startActiveSpan() methodology can be added to the energetic span as a toddler span.

Set off the exploratory trace-based take a look at as soon as once more to see what it seems to be like. However, now you’ve included the take a look at spec. You’ll get a take a look at abstract within the CLI and it’ll even be mirrored within the Net UI.

tracetest run take a look at -f path-to-dir/exploratory-test.yaml

[Output]
✔ Fee: Exploratory take a look at of bank card (http://localhost:11633/take a look at/payment-valid-credit-card/run/2/take a look at) - hint id: f6d754f3f87ba5cc9da5075037ba266a
    ✔ It must be a legitimate card
Enter fullscreen mode

Exit fullscreen mode

https://res.cloudinary.com/djwdcmwdz/image/upload/v1700047365/Blogposts/blogpost-from-cnl-live/screely-1700047350447_eal9ro.png

Superior work! With the code instrumentation configured accurately, you may transfer on to including checks to cowl all the sting circumstances of the paymentservice.



Creating Hint-based Checks for the Fee Service

The 4 circumstances I would love you to cowl are:

  1. Check if a bank card is legitimate
  2. Check if a bank card is invalid
  3. Check if a bank card has expired
  4. Check if a bank card just isn’t allowed

Let’s soar in.



Check if a Credit score Card is Legitimate

To check the validity of a bank card you’ll add three assertions.

# [...]
specs:
  - identify: It ought to name Cost methodology efficiently
    selector: span[tracetest.span.type="rpc" name="grpc.oteldemo.PaymentService/Charge" rpc.system="grpc" rpc.method="Charge" rpc.service="oteldemo.PaymentService"]
    # as a substitute of returning status_code 0, this service can return 1 relying on timing, but it surely works as supposed
    assertions:
      # updating assertion to match 0 and 1
      - attr:rpc.grpc.status_code <= 1
  - identify: It ought to return a transaction ID
    selector: span[tracetest.span.type="general" name="Tracetest trigger"]
    assertions:
      - attr:tracetest.response.physique | json_path '$.transactionId' != ""
  - identify: It ought to return a legitimate bank card
    selector: span[tracetest.span.type="general" name="charge"]
    assertions: 
      - attr:app.cost.card_valid = "true"
Enter fullscreen mode

Exit fullscreen mode

Because it’s a GRPC API you’ll assert on standing code, the response, and eventually the span attribute validating the bank card. View the full test YAML here.



Check if a Credit score Card is Invalid

To check if a bank card is invalid you’ll add two assertions. The charge.js file has a validity check that throws an error with the "Bank card information is invalid." message.

// cost.js

if (!legitimate) {
  throw new Error('Bank card information is invalid.')
}
Enter fullscreen mode

Exit fullscreen mode

The primary assertion will look to validate that error message. The second assertion will examine for the response standing error code.

# [...]
specs:
  - identify: It ought to name Cost methodology and obtain a gRPC error
    selector: span[tracetest.span.type="rpc" name="grpc.oteldemo.PaymentService/Charge" rpc.system="grpc" rpc.method="Charge" rpc.service="oteldemo.PaymentService"]
    assertions:
    - attr:grpc.error_message = "Bank card information is invalid."
  - identify: It ought to return a return an gRPC error code to the caller
    selector: span[tracetest.span.type="general" name="Tracetest trigger"]
    assertions:
    - attr:tracetest.response.standing = 2
Enter fullscreen mode

Exit fullscreen mode

View the full test YAML here.



Check if a Credit score Card has Expired

To check if a bank card has expired you’ll add two assertions. Just like the invalid error, the charge.js file has an expiration check that throws an error with the "The bank card (ending ${lastFourDigits}) expired on ${month}/${12 months}." message.

// cost.js

if ((currentYear * 12 + currentMonth) > (12 months * 12 + month)) {
  throw new Error(`The bank card (ending ${lastFourDigits}) expired on ${month}/${12 months}.`)
}
Enter fullscreen mode

Exit fullscreen mode

The primary assertion will look to validate that error message. The second assertion will examine for the response standing error code.

# [...]
specs:
  - identify: It ought to name Cost methodology and obtain a gRPC error
    selector: span[tracetest.span.type="rpc" name="grpc.oteldemo.PaymentService/Charge" rpc.system="grpc" rpc.method="Charge" rpc.service="oteldemo.PaymentService"]
    assertions:
    - attr:grpc.error_message = "The bank card (ending 0454) expired on 1/2021."
  - identify: It ought to return a return an gRPC error code to the caller
    selector: span[tracetest.span.type="general" name="Tracetest trigger"]
    assertions:
    - attr:tracetest.response.standing = 2
Enter fullscreen mode

Exit fullscreen mode

View the full test YAML here.



Check if a Credit score Card is Not Allowed

The charge.js has a validity check to make sure only Visa and Mastercard credit cards are allowed. It can throw an error the message "Sorry, we can not course of ${cardType} bank cards. Solely VISA or MasterCard is accepted.".

if (!['visa', 'mastercard'].contains(cardType)) {
  throw new Error(`Sorry, we can not course of ${cardType} bank cards. Solely VISA or MasterCard is accepted.`)
} 
Enter fullscreen mode

Exit fullscreen mode

The primary assertion will look to validate that error message. The second assertion will examine for the response standing error code.

specs:
  - identify: It ought to name Cost methodology and obtain a gRPC error
    selector: span[tracetest.span.type="rpc" name="grpc.oteldemo.PaymentService/Charge" rpc.system="grpc" rpc.method="Charge" rpc.service="oteldemo.PaymentService"]
    assertions:
    - attr:grpc.error_message = "Sorry, we can not course of amex bank cards. Solely VISA or MasterCard is accepted."
  - identify: It ought to return a return an gRPC error code to the caller
    selector: span[tracetest.span.type="general" name="Tracetest trigger"]
    assertions:
    - attr:tracetest.response.standing = 2
Enter fullscreen mode

Exit fullscreen mode

View the full test YAML here.



What you realized about contributing to OpenTelemetry

Right this moment you realized three essential issues.

  1. Easy methods to demystify OpenTelemetry by including computerized and handbook code instrumentation.
  2. Easy methods to use trace-based testing within the OpenTelemetry Demo to take care of function performance and telemetry integrity.
  3. Easy methods to contribute to the OpenTelemetry Demo safely whereas avoiding regressions.

Now you may clearly perceive OpenTelemetry, writing code instrumentation, and incorporating traces into trace-based checks. You are higher ready to contribute significant additions to the OpenTelemetry undertaking and validate your contributions with trace-based testing.

To be taught extra about Tracetest and what it will probably enable you to obtain, examine the docs and check out it out in the present day by signing up at no cost!

Additionally, please be at liberty to affix our Discord community, give Tracetest a star on GitHub, or schedule a time to chat 1:1.

Add a Comment

Your email address will not be published. Required fields are marked *

Want to Contribute to us or want to have 15k+ Audience read your Article ? Or Just want to make a strong Backlink?