Skip to content

Commit

Permalink
Merge pull request #88 from scoutapp/59-detect-application-root
Browse files Browse the repository at this point in the history
Detect application root, add some configurations
  • Loading branch information
Chris Schneider authored Oct 14, 2019
2 parents 467ed5f + 2fb4ece commit 3358236
Show file tree
Hide file tree
Showing 8 changed files with 300 additions and 31 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@

- New `\Scoutapm\Config\ConfigKey` class containing `public const`s for configuration key names (#83)
- Added config key `log_level` which overrides Scout APM's minimum log level (#83)
- Added more new config keys (#88):
- `application_root` (defaults to `composer.json` location, or `$_SERVER['DOCUMENT_ROOT']`
- `scm_subdirectory` (defaults to `.git` location, or `application_root` value)
- `revision_sha` (defaults to version detected by `ocramius/package-versions`)
- `hostname` (defaults to value of `gethostname()`)
- `core_agent_permissions` (defaults to `0777`)
- Added warning when `name` or `key` configurations are not set

### Fixed

Expand Down
24 changes: 22 additions & 2 deletions src/Agent.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
use Scoutapm\Extension\ExtentionCapabilities;
use Scoutapm\Extension\PotentiallyAvailableExtensionCapabilities;
use Scoutapm\Logger\FilteredLogLevelDecorator;
use function is_string;
use function sprintf;

final class Agent implements ScoutApmAgent
{
Expand Down Expand Up @@ -72,11 +74,27 @@ public function __construct(Config $configuration, Connector $connector, LoggerI
);
}

if ($this->config->get(ConfigKey::MONITORING_ENABLED)) {
$this->warnIfConfigValueIsNotSet(ConfigKey::APPLICATION_NAME);
$this->warnIfConfigValueIsNotSet(ConfigKey::APPLICATION_KEY);
}

$this->request = new Request();

$this->ignoredEndpoints = new IgnoredEndpoints($configuration->get(ConfigKey::IGNORED_ENDPOINTS));
}

private function warnIfConfigValueIsNotSet(string $configKey) : void
{
$configValue = $this->config->get($configKey);

if ($configValue !== null && (! is_string($configValue) || $configValue !== '')) {
return;
}

$this->logger->warning(sprintf('Config key "%s" should be set, but it was empty', $configKey));
}

private static function createConnectorFromConfig(Config $config) : SocketConnector
{
return new SocketConnector($config->get(ConfigKey::CORE_AGENT_SOCKET_PATH));
Expand Down Expand Up @@ -120,7 +138,8 @@ public function connect() : void
$this->config->get(ConfigKey::CORE_AGENT_DIRECTORY) . '/' . $this->config->get(ConfigKey::CORE_AGENT_FULL_NAME),
$this->config->get(ConfigKey::CORE_AGENT_FULL_NAME),
$this->logger,
$this->config->get(ConfigKey::CORE_AGENT_DOWNLOAD_URL)
$this->config->get(ConfigKey::CORE_AGENT_DOWNLOAD_URL),
$this->config->get(ConfigKey::CORE_AGENT_PERMISSIONS)
)
);
$manager->launch();
Expand Down Expand Up @@ -275,7 +294,8 @@ public function send() : bool
}

if (! $this->connector->sendCommand(new Metadata(
new DateTimeImmutable('now', new DateTimeZone('UTC'))
new DateTimeImmutable('now', new DateTimeZone('UTC')),
$this->config
))) {
return false;
}
Expand Down
5 changes: 5 additions & 0 deletions src/Config/ConfigKey.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ abstract class ConfigKey
public const LOG_LEVEL = 'log_level';
public const API_VERSION = 'api_version';
public const IGNORED_ENDPOINTS = 'ignore';
public const APPLICATION_ROOT = 'application_root';
public const SCM_SUBDIRECTORY = 'scm_subdirectory';
public const REVISION_SHA = 'revision_sha';
public const HOSTNAME = 'hostname';
public const CORE_AGENT_LOG_LEVEL = 'core_agent_log_level';
public const CORE_AGENT_LOG_FILE = 'core_agent_log_file';
public const CORE_AGENT_CONFIG_FILE = 'core_agent_config_file';
Expand All @@ -23,4 +27,5 @@ abstract class ConfigKey
public const CORE_AGENT_DOWNLOAD_ENABLED = 'core_agent_download';
public const CORE_AGENT_VERSION = 'core_agent_version';
public const CORE_AGENT_TRIPLE = 'core_agent_triple';
public const CORE_AGENT_PERMISSIONS = 'core_agent_permissions';
}
7 changes: 4 additions & 3 deletions src/Config/Source/DefaultSource.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
/** @internal */
class DefaultSource
{
/** @var array<string, (string|bool|array<int, string>)> */
/** @var array<string, (string|bool|array<int, string>|int)> */
private $defaults;

public function __construct()
Expand All @@ -37,7 +37,7 @@ public function hasKey(string $key) : bool
*
* Only valid if the Source has previously returned "true" to `hasKey`
*
* @return string|bool|array<int, string>|null
* @return string|bool|array<int, string>|int|null
*/
public function get(string $key)
{
Expand All @@ -49,7 +49,7 @@ public function get(string $key)
*
* Only valid if the Source has previously returned "true" to `hasKey`
*
* @return array<string, (string|bool|array<int, string>)>
* @return array<string, (string|bool|array<int, string>|int)>
*/
private function getDefaultConfig() : array
{
Expand All @@ -60,6 +60,7 @@ private function getDefaultConfig() : array
ConfigKey::CORE_AGENT_LAUNCH_ENABLED => true,
ConfigKey::CORE_AGENT_VERSION => 'v1.2.2',
ConfigKey::CORE_AGENT_DOWNLOAD_URL => 'https://s3-us-west-1.amazonaws.com/scout-public-downloads/apm_core_agent/release',
ConfigKey::CORE_AGENT_PERMISSIONS => 0777,
ConfigKey::MONITORING_ENABLED => false,
ConfigKey::IGNORED_ENDPOINTS => [],
ConfigKey::LOG_LEVEL => 'debug',
Expand Down
26 changes: 18 additions & 8 deletions src/CoreAgent/Downloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,16 @@ class Downloader
/** @var string */
private $downloadUrl;

public function __construct(string $coreAgentDir, string $coreAgentFullName, LoggerInterface $logger, string $downloadUrl)
{
/** @var int */
private $coreAgentPermissions;

public function __construct(
string $coreAgentDir,
string $coreAgentFullName,
LoggerInterface $logger,
string $downloadUrl,
int $coreAgentPermissions
) {
$this->logger = $logger;

$this->coreAgentDir = $coreAgentDir;
Expand All @@ -77,9 +85,10 @@ public function __construct(string $coreAgentDir, string $coreAgentFullName, Log
*
* @link https://bugs.php.net/bug.php?id=58852
*/
$this->package_location = $coreAgentDir . '/' . str_replace('.', '_', $coreAgentFullName) . '.tgz';
$this->download_lock_path = $coreAgentDir . '/download.lock';
$this->downloadUrl = $downloadUrl;
$this->package_location = $coreAgentDir . '/' . str_replace('.', '_', $coreAgentFullName) . '.tgz';
$this->download_lock_path = $coreAgentDir . '/download.lock';
$this->downloadUrl = $downloadUrl;
$this->coreAgentPermissions = $coreAgentPermissions;
}

public function download() : void
Expand All @@ -104,12 +113,13 @@ public function download() : void
private function createCoreAgentDir() : void
{
try {
$permissions = 0777; // TODO: AgentContext.instance.config.core_agent_permissions()
$recursive = true;
$destination = $this->coreAgentDir;

if (! is_dir($destination)) {
mkdir($destination, $permissions, $recursive);
if (! is_dir($destination)
&& ! mkdir($destination, $this->coreAgentPermissions, $recursive)
&& ! is_dir($destination)) {
throw new RuntimeException(sprintf('Directory "%s" was not created', $destination));
}
} catch (Throwable $e) {
$this->logger->error('Failed to create directory: ' . $destination);
Expand Down
84 changes: 78 additions & 6 deletions src/Events/Metadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,22 @@

use DateTimeImmutable;
use PackageVersions\Versions;
use Scoutapm\Config;
use Scoutapm\Config\ConfigKey;
use Scoutapm\Connector\Command;
use Scoutapm\Helper\Timer;
use const PHP_VERSION;
use function array_key_exists;
use function array_keys;
use function array_map;
use function dirname;
use function explode;
use function file_exists;
use function getenv;
use function gethostname;
use function is_readable;
use function is_string;
use function realpath;

/**
* Also called AppServerLoad in other agents
Expand All @@ -24,11 +33,15 @@ final class Metadata implements Command
/** @var Timer */
private $timer;

public function __construct(DateTimeImmutable $now)
/** @var Config */
private $config;

public function __construct(DateTimeImmutable $now, Config $config)
{
// Construct and stop the timer to use its timestamp logic. This event
// is a single point in time, not a range.
$this->timer = new Timer((float) $now->format('U.u'));
$this->timer = new Timer((float) $now->format('U.u'));
$this->config = $config;
}

/**
Expand All @@ -44,20 +57,79 @@ private function data() : array
'framework_version' => '',
'environment' => '',
'app_server' => '',
'hostname' => gethostname(),
'hostname' => $this->config->get(ConfigKey::HOSTNAME) ?? gethostname(),
'database_engine' => '',
'database_adapter' => '',
'application_name' => '',
'application_name' => $this->config->get(ConfigKey::APPLICATION_NAME) ?? '',
'libraries' => $this->getLibraries(),
'paas' => '',
'application_root' => '',
'scm_subdirectory' => '',
'application_root' => $this->applicationRoot(),
'scm_subdirectory' => $this->scmSubdirectory(),
'git_sha' => $this->rootPackageGitSha(),
];
}

/**
* Try to locate a file or folder in any parent directory (upwards of this library itself)
*/
private function locateFileOrFolder(string $fileOrFolder) : ?string
{
// Starting 3 levels up will avoid finding scout-apm-php's own contents
$dir = dirname(__DIR__, 3);
$rootOrHome = '/';

while (dirname($dir) !== $dir && $dir !== $rootOrHome) {
$fileOrFolderAttempted = $dir . '/' . $fileOrFolder;
if (file_exists($fileOrFolderAttempted) && is_readable($fileOrFolderAttempted)) {
return realpath($dir);
}
$dir = dirname($dir);
}

return null;
}

private function applicationRoot() : string
{
$applicationRootConfiguration = $this->config->get(ConfigKey::APPLICATION_ROOT);
if (is_string($applicationRootConfiguration) && $applicationRootConfiguration !== '') {
return $applicationRootConfiguration;
}

$composerJsonLocation = $this->locateFileOrFolder('composer.json');
if ($composerJsonLocation !== null) {
return $composerJsonLocation;
}

if (! array_key_exists('DOCUMENT_ROOT', $_SERVER)) {
return '';
}

return $_SERVER['DOCUMENT_ROOT'];
}

private function scmSubdirectory() : string
{
$scmSubdirectoryConfiguration = $this->config->get(ConfigKey::SCM_SUBDIRECTORY);
if (is_string($scmSubdirectoryConfiguration) && $scmSubdirectoryConfiguration !== '') {
return $scmSubdirectoryConfiguration;
}

return $this->locateFileOrFolder('.git') ?? $this->applicationRoot();
}

private function rootPackageGitSha() : string
{
$revisionShaConfiguration = $this->config->get(ConfigKey::REVISION_SHA);
if (is_string($revisionShaConfiguration) && $revisionShaConfiguration !== '') {
return $revisionShaConfiguration;
}

$herokuSlugCommit = getenv('HEROKU_SLUG_COMMIT');
if (is_string($herokuSlugCommit) && $herokuSlugCommit !== '') {
return $herokuSlugCommit;
}

return explode('@', Versions::getVersion(Versions::ROOT_PACKAGE_NAME))[1];
}

Expand Down
Loading

0 comments on commit 3358236

Please sign in to comment.