Line data Source code
1 : // Copyright The OpenTelemetry Authors
2 : // SPDX-License-Identifier: Apache-2.0
3 :
4 : // Native (VM / Flutter mobile / Flutter desktop) implementations of the
5 : // resource detectors that read from `dart:io`. Imported only on
6 : // non-web platforms via the conditional export in `native_detectors.dart`.
7 :
8 : import 'dart:io' as io;
9 :
10 : import 'package:dartastic_opentelemetry_api/dartastic_opentelemetry_api.dart';
11 :
12 : import 'resource.dart';
13 : import 'resource_detector.dart';
14 :
15 : /// Detects process-related resource information.
16 : ///
17 : /// Populates resource attributes with information about the current process
18 : /// (executable name, command line, runtime). Native-only — `dart:io` is
19 : /// not available in the browser.
20 : ///
21 : /// Semantic conventions:
22 : /// https://opentelemetry.io/docs/specs/semconv/resource/process/
23 : class ProcessResourceDetector implements ResourceDetector {
24 58 : @override
25 : Future<Resource> detect() async {
26 58 : if (OTelFactory.otelFactory == null) {
27 1 : throw StateError('OTel initialize must be called first.');
28 : }
29 : // Keys come from the generated registry enums (never string literals),
30 : // so a typo is a compile error — the class of bug that put the hostname
31 : // in host.arch (#90).
32 58 : return ResourceCreate.create(
33 174 : OTelFactory.otelFactory!.attributesFromMap(<String, Object>{
34 116 : ProcessAttributes.processExecutableName.key: io.Platform.executable,
35 58 : ProcessAttributes.processCommandLine.key:
36 116 : io.Platform.executableArguments.join(' '),
37 58 : ProcessAttributes.processRuntimeName.key: 'dart',
38 116 : ProcessAttributes.processRuntimeVersion.key: io.Platform.version,
39 : }),
40 : );
41 : }
42 : }
43 :
44 : /// Detects host-related resource information.
45 : ///
46 : /// Populates resource attributes with information about the host machine
47 : /// (hostname, architecture, OS details). Native-only — `dart:io` is not
48 : /// available in the browser.
49 : ///
50 : /// Semantic conventions:
51 : /// https://opentelemetry.io/docs/specs/semconv/resource/host/
52 : class HostResourceDetector implements ResourceDetector {
53 57 : @override
54 : Future<Resource> detect() async {
55 57 : if (OTelFactory.otelFactory == null) {
56 1 : throw StateError('OTel initialize must be called first.');
57 : }
58 57 : final attributes = <String, Object>{
59 171 : Host.hostName.key: io.Platform.localHostname,
60 171 : if (_hostArch() case final arch?) Host.hostArch.key: arch,
61 171 : Os.osName.key: io.Platform.operatingSystem,
62 171 : Os.osVersion.key: io.Platform.operatingSystemVersion,
63 : };
64 :
65 57 : final osType = switch (io.Platform.operatingSystem) {
66 57 : 'linux' => 'linux',
67 0 : 'windows' => 'windows',
68 0 : 'macos' => 'macos',
69 0 : 'android' => 'android',
70 0 : 'ios' => 'ios',
71 : _ => null,
72 : };
73 : if (osType != null) {
74 114 : attributes[Os.osType.key] = osType;
75 : }
76 :
77 57 : return ResourceCreate.create(
78 114 : OTelFactory.otelFactory!.attributesFromMap(attributes),
79 : );
80 : }
81 : }
82 :
83 : /// Resolves `host.arch` to a registry value (`amd64`, `arm64`, `arm32`,
84 : /// `x86`, `riscv64`, …) from the runtime's `Platform.version`, whose tail
85 : /// reads `on "<os>_<arch>"`. Pure Dart, no `dart:ffi`. Returns `null` when
86 : /// the token can't be parsed, so the attribute is simply omitted.
87 57 : String? _hostArch() {
88 : final match =
89 171 : RegExp(r'on "[a-z0-9]+_([a-z0-9]+)"').firstMatch(io.Platform.version);
90 57 : return switch (match?.group(1)) {
91 57 : 'arm64' => 'arm64',
92 57 : 'arm' => 'arm32',
93 57 : 'x64' => 'amd64',
94 0 : 'ia32' => 'x86',
95 0 : 'riscv64' => 'riscv64',
96 0 : 'riscv32' => 'riscv32',
97 : final other => other, // pass through unknown tokens; null omits it
98 : };
99 : }
|