adding container detector (#933)
detect container id from cgroup or mountinfo
This commit is contained in:
parent
746d25a7d1
commit
88ea7c3024
|
@ -165,6 +165,7 @@ interface KnownValues
|
|||
public const VALUE_DETECTORS_PROCESS_RUNTIME = 'process_runtime';
|
||||
public const VALUE_DETECTORS_SDK = 'sdk';
|
||||
public const VALUE_DETECTORS_SDK_PROVIDED = 'sdk_provided';
|
||||
public const VALUE_DETECTORS_CONTAINER = 'container';
|
||||
public const OTEL_PHP_DETECTORS = [
|
||||
self::VALUE_ALL,
|
||||
self::VALUE_DETECTORS_ENVIRONMENT,
|
||||
|
@ -174,6 +175,7 @@ interface KnownValues
|
|||
self::VALUE_DETECTORS_PROCESS_RUNTIME,
|
||||
self::VALUE_DETECTORS_SDK,
|
||||
self::VALUE_DETECTORS_SDK_PROVIDED,
|
||||
self::VALUE_DETECTORS_CONTAINER,
|
||||
self::VALUE_NONE,
|
||||
];
|
||||
}
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OpenTelemetry\SDK\Resource\Detectors;
|
||||
|
||||
use OpenTelemetry\SDK\Common\Attribute\Attributes;
|
||||
use OpenTelemetry\SDK\Resource\ResourceDetectorInterface;
|
||||
use OpenTelemetry\SDK\Resource\ResourceInfo;
|
||||
use OpenTelemetry\SemConv\ResourceAttributes;
|
||||
|
||||
/**
|
||||
* @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.18.0/specification/resource/semantic_conventions/container.md
|
||||
*/
|
||||
final class Container implements ResourceDetectorInterface
|
||||
{
|
||||
private string $dir;
|
||||
private const CONTAINER_ID_LENGTH = 64;
|
||||
private const CGROUP_V1 = 'cgroup';
|
||||
private const CGROUP_V2 = 'mountinfo';
|
||||
private const HOSTNAME = 'hostname';
|
||||
|
||||
public function __construct(string $dir = '/proc/self')
|
||||
{
|
||||
$this->dir = $dir;
|
||||
}
|
||||
|
||||
public function getResource(): ResourceInfo
|
||||
{
|
||||
$attributes = [];
|
||||
$id = $this->getContainerId();
|
||||
if ($id) {
|
||||
$attributes[ResourceAttributes::CONTAINER_ID] = $id;
|
||||
}
|
||||
|
||||
return ResourceInfo::create(Attributes::create($attributes), ResourceAttributes::SCHEMA_URL);
|
||||
}
|
||||
|
||||
private function getContainerId(): ?string
|
||||
{
|
||||
return $this->getContainerIdV2() ?? $this->getContainerIdV1();
|
||||
}
|
||||
|
||||
private function getContainerIdV1(): ?string
|
||||
{
|
||||
$data = file_get_contents(sprintf('%s/%s', $this->dir, self::CGROUP_V1));
|
||||
if (!$data) {
|
||||
return null;
|
||||
}
|
||||
$lines = explode('\n', $data);
|
||||
foreach ($lines as $line) {
|
||||
if (strlen($line) >= self::CONTAINER_ID_LENGTH) {
|
||||
//if string is longer than CONTAINER_ID_LENGTH, return the last CONTAINER_ID_LENGTH chars
|
||||
return substr($line, strlen($line) - self::CONTAINER_ID_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
private function getContainerIdV2(): ?string
|
||||
{
|
||||
$data = file_get_contents(sprintf('%s/%s', $this->dir, self::CGROUP_V2));
|
||||
if (!$data) {
|
||||
return null;
|
||||
}
|
||||
$lines = explode(PHP_EOL, $data);
|
||||
foreach ($lines as $line) {
|
||||
if (strpos($line, self::HOSTNAME) !== false) {
|
||||
$parts = explode('/', $line);
|
||||
foreach ($parts as $part) {
|
||||
if (strlen($part) === self::CONTAINER_ID_LENGTH) {
|
||||
return $part;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -44,6 +44,7 @@ class ResourceInfoFactory
|
|||
new Detectors\ProcessRuntime(),
|
||||
new Detectors\Sdk(),
|
||||
new Detectors\SdkProvided(),
|
||||
new Detectors\Container(),
|
||||
]))->getResource();
|
||||
}
|
||||
|
||||
|
@ -78,6 +79,10 @@ class ResourceInfoFactory
|
|||
case Values::VALUE_DETECTORS_SDK_PROVIDED:
|
||||
$resourceDetectors[] = new Detectors\SdkProvided();
|
||||
|
||||
break;
|
||||
case Values::VALUE_DETECTORS_CONTAINER:
|
||||
$resourceDetectors[] = new Detectors\Container();
|
||||
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OpenTelemetry\Example\Unit\SDK\Resource\Detectors;
|
||||
|
||||
use OpenTelemetry\SDK\Resource\Detectors\Container;
|
||||
use OpenTelemetry\SemConv\ResourceAttributes;
|
||||
use org\bovigo\vfs\vfsStream;
|
||||
use org\bovigo\vfs\vfsStreamFile;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @covers OpenTelemetry\SDK\Resource\Detectors\Container
|
||||
*/
|
||||
class ContainerTest extends TestCase
|
||||
{
|
||||
private vfsStreamFile $cgroup;
|
||||
private vfsStreamFile $mountinfo;
|
||||
private Container $detector;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
$root = vfsStream::setup();
|
||||
$this->cgroup = vfsStream::newFile('cgroup')->at($root);
|
||||
$this->mountinfo = vfsStream::newFile('mountinfo')->at($root);
|
||||
$this->detector = new Container($root->url());
|
||||
}
|
||||
|
||||
public function test_valid_v1(): void
|
||||
{
|
||||
$valid = 'a8493b8a4f6f23b65c5db50be86619ca4da078da040aa3d5ccff26fe50de205d';
|
||||
$this->cgroup->setContent($valid);
|
||||
$resource = $this->detector->getResource();
|
||||
|
||||
$this->assertSame(ResourceAttributes::SCHEMA_URL, $resource->getSchemaUrl());
|
||||
$this->assertIsString($resource->getAttributes()->get(ResourceAttributes::CONTAINER_ID));
|
||||
$this->assertSame($valid, $resource->getAttributes()->get(ResourceAttributes::CONTAINER_ID));
|
||||
}
|
||||
|
||||
public function test_invalid_v1(): void
|
||||
{
|
||||
$this->cgroup->setContent('0::/');
|
||||
$resource = $this->detector->getResource();
|
||||
|
||||
$this->assertEmpty($resource->getAttributes());
|
||||
}
|
||||
|
||||
public function test_valid_v2(): void
|
||||
{
|
||||
$expected = 'a8493b8a4f6f23b65c5db50be86619ca4da078da040aa3d5ccff26fe50de205d';
|
||||
$data = <<< EOS
|
||||
1366 1365 0:30 / /sys/fs/cgroup ro,nosuid,nodev,noexec,relatime - cgroup2 cgroup rw
|
||||
1408 1362 0:107 / /dev/mqueue rw,nosuid,nodev,noexec,relatime - mqueue mqueue rw
|
||||
1579 1362 0:112 / /dev/shm rw,nosuid,nodev,noexec,relatime - tmpfs shm rw,size=65536k,inode64
|
||||
1581 1359 259:2 /var/lib/docker/containers/a8493b8a4f6f23b65c5db50be86619ca4da078da040aa3d5ccff26fe50de205d/hostname /etc/hostname rw,relatime - ext4 /dev/nvme0n1p2 rw,errors=remount-ro
|
||||
1583 1359 259:3 /brett/docker/otel/opentelemetry-php /usr/src/myapp rw,relatime - ext4 /dev/nvme0n1p3 rw
|
||||
EOS;
|
||||
$this->mountinfo->withContent($data);
|
||||
$resource = $this->detector->getResource();
|
||||
|
||||
$this->assertCount(1, $resource->getAttributes());
|
||||
$this->assertSame($expected, $resource->getAttributes()->get(ResourceAttributes::CONTAINER_ID));
|
||||
}
|
||||
|
||||
public function test_invalid_v2(): void
|
||||
{
|
||||
$data = <<< EOS
|
||||
1581 1359 259:2 /var/lib/docker/containers/a8493b8a4f6f23b65c5db50be86619ca4da078da040aa3d5ccff26fe50de205d/wrongkeyword
|
||||
EOS;
|
||||
$this->mountinfo->withContent($data);
|
||||
$resource = $this->detector->getResource();
|
||||
|
||||
$this->assertEmpty($resource->getAttributes());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue