Skip to content
This repository has been archived by the owner on Feb 1, 2024. It is now read-only.

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
norberttech committed Feb 21, 2019
1 parent 15f8f93 commit 965ff9c
Show file tree
Hide file tree
Showing 19 changed files with 737 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/vendor/
composer.lock
1 change: 1 addition & 0 deletions .php_cs.cache
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"php":"7.3.0","version":"2.15.0-DEV:dev-master#51209a633d558ee9f53c1255ff9d06dbe0d7d404","rules":{"binary_operator_spaces":true,"blank_line_after_opening_tag":true,"blank_line_before_statement":{"statements":["return"]},"braces":{"allow_single_line_closure":true},"cast_spaces":true,"class_attributes_separation":{"elements":["method"]},"class_definition":{"single_line":true},"concat_space":{"spacing":"none"},"declare_equal_normalize":true,"function_typehint_space":true,"include":true,"increment_style":true,"lowercase_cast":true,"lowercase_static_reference":true,"magic_constant_casing":true,"magic_method_casing":true,"method_argument_space":true,"native_function_casing":true,"new_with_braces":true,"no_blank_lines_after_class_opening":true,"no_blank_lines_after_phpdoc":true,"no_empty_comment":true,"no_empty_phpdoc":true,"no_empty_statement":true,"no_extra_blank_lines":{"tokens":["curly_brace_block","extra","parenthesis_brace_block","square_brace_block","throw","use"]},"no_leading_import_slash":true,"no_leading_namespace_whitespace":true,"no_mixed_echo_print":{"use":"echo"},"no_multiline_whitespace_around_double_arrow":true,"no_short_bool_cast":true,"no_singleline_whitespace_before_semicolons":true,"no_spaces_around_offset":true,"no_trailing_comma_in_list_call":true,"no_trailing_comma_in_singleline_array":true,"no_unneeded_control_parentheses":true,"no_unneeded_curly_braces":true,"no_unneeded_final_method":true,"no_unused_imports":true,"no_whitespace_before_comma_in_array":true,"no_whitespace_in_blank_line":true,"normalize_index_brace":true,"object_operator_without_whitespace":true,"php_unit_fqcn_annotation":true,"phpdoc_align":{"tags":["method","param","property","return","throws","type","var"]},"phpdoc_annotation_without_dot":true,"phpdoc_indent":true,"phpdoc_inline_tag":true,"phpdoc_no_access":true,"phpdoc_no_alias_tag":true,"phpdoc_no_empty_return":true,"phpdoc_no_package":true,"phpdoc_no_useless_inheritdoc":true,"phpdoc_return_self_reference":true,"phpdoc_scalar":true,"phpdoc_separation":true,"phpdoc_single_line_var_spacing":true,"phpdoc_summary":true,"phpdoc_to_comment":true,"phpdoc_trim":true,"phpdoc_types":true,"phpdoc_types_order":{"null_adjustment":"always_last","sort_algorithm":"none"},"phpdoc_var_without_name":true,"return_type_declaration":true,"semicolon_after_instruction":true,"short_scalar_cast":true,"single_blank_line_before_namespace":true,"single_class_element_per_statement":true,"single_line_comment_style":{"comment_types":["hash"]},"single_quote":true,"space_after_semicolon":{"remove_in_empty_for_expressions":true},"standardize_increment":true,"standardize_not_equals":true,"ternary_operator_spaces":true,"trailing_comma_in_multiline_array":true,"trim_array_spaces":true,"unary_operator_spaces":true,"whitespace_after_comma_in_array":true,"yoda_style":true,"blank_line_after_namespace":true,"elseif":true,"function_declaration":true,"indentation_type":true,"line_ending":true,"lowercase_constants":true,"lowercase_keywords":true,"no_break_comment":true,"no_closing_tag":true,"no_spaces_after_function_name":true,"no_spaces_inside_parenthesis":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_import_per_statement":true,"single_line_after_imports":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"visibility_required":true,"encoding":true,"full_opening_tag":true,"dir_constant":true,"ereg_to_preg":true,"error_suppression":true,"fopen_flag_order":true,"fopen_flags":{"b_mode":false},"function_to_constant":true,"implode_call":true,"is_null":true,"modernize_types_casting":true,"native_constant_invocation":{"fix_built_in":false,"include":["DIRECTORY_SEPARATOR","PHP_SAPI","PHP_VERSION_ID"],"scope":"namespaced"},"native_function_invocation":{"include":["@compiler_optimized"],"scope":"namespaced","strict":true},"no_alias_functions":true,"no_homoglyph_names":true,"non_printable_character":{"use_escape_sequences_in_strings":false},"php_unit_construct":true,"psr4":true,"self_accessor":true,"set_type_to_cast":true,"php_unit_namespaced":{"target":"4.8"},"php_unit_dedicate_assert":{"target":"3.5"},"array_syntax":{"syntax":"short"}},"hashes":{"Listener\/ExceptionListener.php":1866649734,"Listener\/KernelTerminateListener.php":543787777,"Listener\/HttpRequestListener.php":4197278271,"Tests\/DependencyInjection\/AppInsightsPHPExtensionTest.php":2108197485,"Tests\/DependencyInjection\/ConfigurationTest.php":2895939776,"AppInsightsPHPBundle.php":1078031753,"DependencyInjection\/Configuration.php":4136112126,"DependencyInjection\/AppInsightsPHPExtension.php":169054178,"DependencyInjection\/Compiler\/DoctrineDependencyPassPass.php":3326885398}}
16 changes: 16 additions & 0 deletions .php_cs.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

$finder = PhpCsFixer\Finder::create()
->in([__DIR__ . '/']);

return PhpCsFixer\Config::create()
->setRules([
'@Symfony' => true,
'@Symfony:risky' => true,
'@PHPUnit48Migration:risky' => true,
'php_unit_no_expectation_annotation' => false,
'array_syntax' => ['syntax' => 'short'],
'protected_to_private' => false,
])
->setRiskyAllowed(true)
->setFinder($finder);
57 changes: 57 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
language: php
sudo: false
cache:
directories:
- $HOME/.composer/cache/files
- $HOME/symfony-bridge/.phpunit

env:
global:
- PHPUNIT_FLAGS="-v"
- SYMFONY_PHPUNIT_DIR="$HOME/symfony-bridge/.phpunit"

matrix:
fast_finish: true
include:
# Minimum supported dependencies with the latest and oldest PHP version
- php: 7.2
env: COMPOSER_FLAGS="--prefer-stable --prefer-lowest" SYMFONY_DEPRECATIONS_HELPER="weak_vendors"
- php: 7.1
env: COMPOSER_FLAGS="--prefer-stable --prefer-lowest" SYMFONY_DEPRECATIONS_HELPER="weak_vendors"

# Test the latest stable release
- php: 7.1
- php: 7.2
env: COVERAGE=true PHPUNIT_FLAGS="-v --coverage-text"

# Test LTS versions. This makes sure we do not use Symfony packages with version greater
# than 2 or 3 respectively. Read more at https://github.com/symfony/lts
- php: 7.2
env: DEPENDENCIES="symfony/lts:^2"
- php: 7.2
env: DEPENDENCIES="symfony/lts:^3"

# Latest commit to master
- php: 7.2
env: STABILITY="dev"

allow_failures:
# Dev-master is allowed to fail.
- env: STABILITY="dev"

before_install:
- if [[ $COVERAGE != true ]]; then phpenv config-rm xdebug.ini || true; fi
- if ! [ -z "$STABILITY" ]; then composer config minimum-stability ${STABILITY}; fi;
- if ! [ -v "$DEPENDENCIES" ]; then composer require --no-update ${DEPENDENCIES}; fi;

install:
# To be removed when this issue will be resolved: https://github.com/composer/composer/issues/5355
- if [[ "$COMPOSER_FLAGS" == *"--prefer-lowest"* ]]; then composer update --prefer-dist --no-interaction --prefer-stable --quiet; fi
- composer update ${COMPOSER_FLAGS} --prefer-dist --no-interaction
- ./vendor/bin/simple-phpunit install

script:
- composer validate --strict --no-check-lock
# simple-phpunit is the PHPUnit wrapper provided by the PHPUnit Bridge component and
# it helps with testing legacy code and deprecations (composer require symfony/phpunit-bridge)
- ./vendor/bin/simple-phpunit $PHPUNIT_FLAGS
17 changes: 17 additions & 0 deletions AppInsightsPHPBundle.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace AppInsightsPHP\Symfony\AppInsightsPHPBundle;

use AppInsightsPHP\Symfony\AppInsightsPHPBundle\DependencyInjection\Compiler\DoctrineDependencyPassPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;

final class AppInsightsPHPBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
$container->addCompilerPass(new DoctrineDependencyPassPass());
}
}
68 changes: 68 additions & 0 deletions DependencyInjection/AppInsightsPHPExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

declare(strict_types=1);

namespace AppInsightsPHP\Symfony\AppInsightsPHPBundle\DependencyInjection;

use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;

final class AppInsightsPHPExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$config = $this->processConfiguration($this->getConfiguration($configs, $container), $configs);

$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('app_insights_php.xml');
$loader->load('app_insights_php_monolog.xml');

$container->setParameter('app_insights_php.instrumentation_key', $config['instrumentation_key']);
$container->setParameter('app_insights_php.doctrine.track_dependency', $config['doctrine']['track_dependency']);

if ($config['doctrine']['track_dependency']) {
if (!\class_exists('AppInsightsPHP\\Doctrine\\DBAL\\Logging\\DependencyLogger')) {
throw new \RuntimeException('Please first run `composer require download app-insights-php/doctrine-dependency-logger` if you want to log DBAL queries.');
}

$loader->load('app_insights_php_doctrine.xml');
}

$container->setDefinition('app_insights_php.configuration.exceptions',
new Definition(\AppInsightsPHP\Client\Configuration\Exceptions::class, [
$config['exceptions']['enabled'],
(array) $config['exceptions']['ignored_exceptions'],
])
);
$container->setDefinition('app_insights_php.configuration.dependencies',
new Definition(\AppInsightsPHP\Client\Configuration\Dependenies::class, [
$config['dependencies']['enabled'],
])
);
$container->setDefinition('app_insights_php.configuration.requests',
new Definition(\AppInsightsPHP\Client\Configuration\Requests::class, [
$config['requests']['enabled'],
])
);
$container->setDefinition('app_insights_php.configuration.traces',
new Definition(\AppInsightsPHP\Client\Configuration\Traces::class, [
$config['traces']['enabled'],
])
);
$container->setDefinition('app_insights_php.configuration',
new Definition(\AppInsightsPHP\Client\Configuration::class, [
$config['enabled'],
new Reference('app_insights_php.configuration.exceptions'),
new Reference('app_insights_php.configuration.dependencies'),
new Reference('app_insights_php.configuration.requests'),
new Reference('app_insights_php.configuration.traces'),
])
);

$container->getDefinition('app_insights_php.telemetry.factory')->replaceArgument(1, new Reference('app_insights_php.configuration'));
}
}
27 changes: 27 additions & 0 deletions DependencyInjection/Compiler/DoctrineDependencyPassPass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace AppInsightsPHP\Symfony\AppInsightsPHPBundle\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

final class DoctrineDependencyPassPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (false === $container->getParameter('app_insights_php.doctrine.track_dependency')) {
return;
}

$doctrine = $container->getParameter('doctrine.connections');

foreach ($doctrine as $connectionId) {
$container
->getDefinition(sprintf('%s.configuration', $connectionId))
->addMethodCall('setSQLLogger', [new Reference('app_insights_php.doctrine.logger.dependency')]);
}
}
}
59 changes: 59 additions & 0 deletions DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

declare(strict_types=1);

namespace AppInsightsPHP\Symfony\AppInsightsPHPBundle\DependencyInjection;

use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;

final class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder('app_insights_php');
$rootNode = method_exists(TreeBuilder::class, 'getRootNode') ? $treeBuilder->getRootNode() : $treeBuilder->root('app_insights_php');

$rootNode
->children()
->booleanNode('enabled')->defaultTrue()->end()
->scalarNode('instrumentation_key')->isRequired()->cannotBeEmpty()->end()
->arrayNode('exceptions')
->addDefaultsIfNotSet()
->children()
->booleanNode('enabled')->defaultTrue()->end()
->arrayNode('ignored_exceptions')
->scalarPrototype()->end()
->end()
->end()
->end()
->arrayNode('dependencies')
->addDefaultsIfNotSet()
->children()
->booleanNode('enabled')->defaultTrue()->end()
->end()
->end()
->arrayNode('traces')
->addDefaultsIfNotSet()
->children()
->booleanNode('enabled')->defaultTrue()->end()
->end()
->end()
->arrayNode('requests')
->addDefaultsIfNotSet()
->children()
->booleanNode('enabled')->defaultTrue()->end()
->end()
->end()
->arrayNode('doctrine')
->addDefaultsIfNotSet()
->children()
->booleanNode('track_dependency')->defaultFalse()->end()
->end()
->end()
->end()
;

return $treeBuilder;
}
}
39 changes: 39 additions & 0 deletions Listener/ExceptionListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

declare(strict_types=1);

namespace AppInsightsPHP\Symfony\AppInsightsPHPBundle\Listener;

use AppInsightsPHP\Client\Client;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\KernelEvents;

final class ExceptionListener implements EventSubscriberInterface
{
private $telemetryClient;
private $exceptionLogged;

public function __construct(Client $telemetryClient)
{
$this->telemetryClient = $telemetryClient;
$this->exceptionLogged = false;
}

public static function getSubscribedEvents()
{
return [
KernelEvents::EXCEPTION => ['onException', 1000],
];
}

public function onException(GetResponseForExceptionEvent $event)
{
if ($this->exceptionLogged) {
return;
}

$this->telemetryClient->trackException($event->getException());
$this->exceptionLogged = true;
}
}
75 changes: 75 additions & 0 deletions Listener/HttpRequestListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php

declare(strict_types=1);

namespace AppInsightsPHP\Symfony\AppInsightsPHPBundle\Listener;

use AppInsightsPHP\Client\Client;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;

final class HttpRequestListener implements EventSubscriberInterface
{
private $telemetryClient;

private $request;
private $requestStartTime;
private $requestStartTimeMs;

public function __construct(Client $telemetryClient)
{
$this->telemetryClient = $telemetryClient;
}

public static function getSubscribedEvents()
{
return [
KernelEvents::REQUEST => ['onKernelRequest', 1000],
KernelEvents::RESPONSE => ['onKernelResponse', -1000],
];
}

public function onKernelRequest(GetResponseEvent $event)
{
if (!$event->isMasterRequest()) {
return;
}

$this->requestStartTime = time();
$this->requestStartTimeMs = (int) round(microtime(true) * 1000, 1);

$request = $event->getRequest();

$this->telemetryClient->getContext()->getLocationContext()->setIp($request->getClientIp());

if ($request->hasSession()) {
$this->telemetryClient->getContext()->getSessionContext()->setId($request->getSession()->getId());
}

$this->telemetryClient->getContext()->getOperationContext()->setName($request->getMethod().' '.$request->getPathInfo());

$this->request = $this->telemetryClient->beginRequest(
$request->getMethod().' '.$request->getPathInfo(),
$request->getUriForPath($request->getPathInfo()),
$this->requestStartTime
);
}

public function onKernelResponse(FilterResponseEvent $event)
{
if (!$event->isMasterRequest()) {
return;
}

$response = $event->getResponse();

$this->telemetryClient->endRequest(
$this->request,
(int) round(microtime(true) * 1000, 1) - $this->requestStartTimeMs,
$response->getStatusCode(),
$response->isSuccessful()
);
}
}
Loading

0 comments on commit 965ff9c

Please sign in to comment.