-
Notifications
You must be signed in to change notification settings - Fork 186
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
detect container id from cgroup or mountinfo
- Loading branch information
Showing
4 changed files
with
163 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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()); | ||
} | ||
} |