Hello World - Send Your First Trace
What You Will Build​
A command-line app that creates three OpenTelemetry spans - a successful greeting, a disk-space warning, and a config-parsing error - and sends traces, logs, and metrics to your Scout collector. After running it you will see all three signal types correlated in TraceX and LogX. This guide covers all 9 officially supported languages.
Prerequisites​
- A Scout account with a collector running (5-Minute Quick Start if you haven't set one up yet)
- The language runtime for the tab you pick installed on your machine
- Your collector endpoint (default
http://localhost:4318)
Choose Your Language​
- Node.js
- Python
- Go
- Java
- C#
- Rust
- PHP
- Ruby
- Elixir
Install Dependencies​
{
"name": "hello-world-nodejs",
"version": "1.0.0",
"private": true,
"dependencies": {
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/api-logs": "^0.213.0",
"@opentelemetry/exporter-logs-otlp-http": "^0.213.0",
"@opentelemetry/exporter-metrics-otlp-http": "^0.213.0",
"@opentelemetry/exporter-trace-otlp-http": "^0.213.0",
"@opentelemetry/resources": "^2.6.0",
"@opentelemetry/sdk-logs": "^0.213.0",
"@opentelemetry/sdk-metrics": "^2.6.0",
"@opentelemetry/sdk-trace-base": "^2.6.0",
"@opentelemetry/sdk-trace-node": "^2.6.0"
}
}
npm install
The Code​
function sayHello(tracer, otelLogger, helloCounter) {
tracer.startActiveSpan("say-hello", (span) => {
otelLogger.emit({
severityText: "INFO",
severityNumber: SeverityNumber.INFO,
body: "Hello, World!",
});
helloCounter.add(1);
span.setAttribute("greeting", "Hello, World!");
span.end();
});
}
The full example also includes checkDiskSpace (warning) and parseConfig
(error with exception).
View full source on GitHub →
Run It​
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 node main.js
Install Dependencies​
opentelemetry-api==1.40.0
opentelemetry-sdk==1.40.0
opentelemetry-exporter-otlp-proto-http==1.40.0
pip install -r requirements.txt
The Code​
def say_hello():
with tracer.start_as_current_span("say-hello") as span:
logger.info("Hello, World!")
hello_counter.add(1)
span.set_attribute("greeting", "Hello, World!")
The full example also includes check_disk_space (warning) and parse_config
(error with exception).
View full source on GitHub →
Run It​
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 python main.py
Install Dependencies​
module hello-world-go
go 1.25.0
require (
go.opentelemetry.io/otel v1.42.0
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.18.0
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.42.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.42.0
go.opentelemetry.io/otel/log v0.18.0
go.opentelemetry.io/otel/metric v1.42.0
go.opentelemetry.io/otel/sdk v1.42.0
go.opentelemetry.io/otel/sdk/log v0.18.0
go.opentelemetry.io/otel/sdk/metric v1.42.0
go.opentelemetry.io/otel/trace v1.42.0
)
go mod tidy
The Code​
func sayHello(ctx context.Context, tracer trace.Tracer, logger log.Logger, counter metric.Int64Counter) {
ctx, span := tracer.Start(ctx, "say-hello")
defer span.End()
var rec log.Record
rec.SetSeverityText("INFO")
rec.SetSeverity(log.SeverityInfo)
rec.SetBody(log.StringValue("Hello, World!"))
logger.Emit(ctx, rec)
counter.Add(ctx, 1)
span.SetAttributes(attribute.String("greeting", "Hello, World!"))
}
The full example also includes checkDiskSpace (warning) and parseConfig
(error with exception).
View full source on GitHub →
Run It​
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 go run .
Install Dependencies​
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-bom</artifactId>
<version>1.60.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-api</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-otlp</artifactId>
</dependency>
</dependencies>
mvn compile
The Code​
static void sayHello(Tracer tracer, Logger logger, LongCounter counter) {
Span span = tracer.spanBuilder("say-hello").startSpan();
try (var scope = span.makeCurrent()) {
logger.logRecordBuilder()
.setSeverity(Severity.INFO)
.setSeverityText("INFO")
.setBody("Hello, World!")
.emit();
counter.add(1);
span.setAttribute("greeting", "Hello, World!");
} finally {
span.end();
}
}
The full example also includes checkDiskSpace (warning) and parseConfig
(error with exception).
View full source on GitHub →
Run It​
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 mvn compile exec:java
Install Dependencies​
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OpenTelemetry" Version="1.15.0" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.15.0" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.15.0" />
</ItemGroup>
</Project>
dotnet restore
The Code​
void SayHello()
{
using var activity = activitySource.StartActivity("say-hello");
activity?.SetTag("greeting", "Hello, World!");
logger.LogInformation("Hello, World!");
helloCounter.Add(1);
}
The full example also includes CheckDiskSpace (warning) and ParseConfig
(error with exception).
View full source on GitHub →
Run It​
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 dotnet run
Install Dependencies​
[package]
name = "hello-world-rust"
version = "0.1.0"
edition = "2021"
[dependencies]
opentelemetry = "0.31.0"
opentelemetry_sdk = { version = "0.31.0", features = ["rt-tokio", "logs", "metrics"] }
opentelemetry-otlp = { version = "0.31.0", features = ["http-proto", "trace", "logs", "metrics"] }
opentelemetry-appender-tracing = "0.31.0"
tokio = { version = "1", features = ["full"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
cargo build
The Code​
fn say_hello(counter: &opentelemetry::metrics::Counter<u64>) {
let tracer = global::tracer("hello-world-rust");
tracer.in_span("say-hello", |cx| {
let span = cx.span();
span.set_attribute(KeyValue::new("greeting", "Hello, World!"));
tracing::info!("Hello, World!");
counter.add(1, &[]);
});
}
The full example also includes check_disk_space (warning) and parse_config
(error with exception).
View full source on GitHub →
Run It​
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 cargo run
Install Dependencies​
{
"require": {
"php": ">=8.1",
"open-telemetry/api": "^1.8",
"open-telemetry/sdk": "^1.13",
"open-telemetry/exporter-otlp": "^1.4",
"php-http/guzzle7-adapter": "^1.1"
}
}
composer install
The Code​
function sayHello(TracerInterface $tracer, $logger, $counter): void {
$span = $tracer->spanBuilder('say-hello')->startSpan();
$scope = $span->activate();
try {
$logger->emit(
(new \OpenTelemetry\API\Logs\LogRecord())
->setSeverityNumber(Severity::INFO)
->setSeverityText('INFO')
->setBody('Hello, World!')
);
$counter->add(1);
$span->setAttribute('greeting', 'Hello, World!');
} finally {
$scope->detach();
$span->end();
}
}
The full example also includes checkDiskSpace (warning) and parseConfig
(error with exception).
View full source on GitHub →
Run It​
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 php main.php
The Ruby OpenTelemetry logs SDK is not yet stable. This example sends traces only and uses span events as log equivalents.
Install Dependencies​
source "https://rubygems.org"
gem "opentelemetry-api", "~> 1.8.0"
gem "opentelemetry-sdk", "~> 1.10.0"
gem "opentelemetry-exporter-otlp", "~> 0.32.0"
bundle install
The Code​
def say_hello(tracer)
tracer.in_span("say-hello") do |span|
span.set_attribute("greeting", "Hello, World!")
span.add_event("greeting.sent", attributes: { "message" => "Hello, World!" })
end
end
The full example also includes check_disk_space (warning event) and
parse_config (error with exception).
View full source on GitHub →
Run It​
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 ruby main.rb
The Elixir OpenTelemetry logs SDK is not yet stable. This example sends traces only and uses span events as log equivalents.
Install Dependencies​
defp deps do
[
{:opentelemetry_api, "~> 1.5"},
{:opentelemetry, "~> 1.7"},
{:opentelemetry_exporter, "~> 1.10"}
]
end
mix deps.get
The Code​
def say_hello do
Tracer.with_span "say-hello" do
Tracer.set_attribute(:greeting, "Hello, World!")
Tracer.add_event("greeting.sent", %{message: "Hello, World!"})
end
end
The full example also includes check_disk_space (warning event) and
parse_config (error with exception).
View full source on GitHub →
Run It​
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 mix run run.exs
Verify in Scout​
- Open TraceX and search for the service name (e.g.
hello-world-nodejs). - Click the trace to see three spans:
say-hello,check-disk-space, andparse-config. - Open LogX - logs from
say-helloand the other spans carry the same trace ID, so you can jump between the trace and its logs. - Check Metrics for the
hello.countcounter.
What Each Span Demonstrates​
| Span | Signals | What it shows |
|---|---|---|
say-hello | trace + log + metric | Normal operation with an INFO log and counter |
check-disk-space | trace + log (or event) | Degraded state with a WARN log |
parse-config | trace + log (or event) | Error path with exception recording and ERROR status |
What's Next​
- Auto-instrumentation guides - add tracing to your real app with zero code changes
- Custom instrumentation - add manual spans, metrics, and logs where auto-instrumentation doesn't reach
- Create Your First Dashboard - visualize the metrics you're collecting
- 5-Minute Quick Start - set up the collector if you haven't already