File: //usr/local/share/elastic_apm/latest/ElasticApm/Impl/AutoInstrument/MemcacheAutoInstrumentation.php
<?php
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/** @noinspection PhpComposerExtensionStubsInspection */
declare(strict_types=1);
namespace Elastic\Apm\Impl\AutoInstrument;
use Elastic\Apm\Impl\AutoInstrument\Util\AutoInstrumentationUtil;
use Elastic\Apm\Impl\Log\LogCategory;
use Elastic\Apm\Impl\Log\Logger;
use Elastic\Apm\Impl\Tracer;
use Memcache;
/**
* Code in this file is part of implementation internals and thus it is not covered by the backward compatibility.
*
* @internal
*/
final class MemcacheAutoInstrumentation extends AutoInstrumentationBase {
private const CLASS_NAME = 'Memcache';
/** @var Logger */
private $logger;
/** @var AutoInstrumentationUtil */
private $util;
private $flush_number = null;
public function __construct(Tracer $tracer) {
parent::__construct($tracer);
$this->logger = $tracer->loggerFactory()->loggerForClass(
LogCategory::AUTO_INSTRUMENTATION,
__NAMESPACE__,
__CLASS__,
__FILE__
)->addContext('this', $this);
$this->util = new AutoInstrumentationUtil($tracer->loggerFactory());
}
public function requiresAttachContextToExternalObjects(): bool {
return true;
}
public function name(): string {
return 'Memcache';
}
public function keywords(): array {
return [ 'Memcache' ];
}
/** @inheritDoc */
public function register(RegistrationContextInterface $ctx): void {
if ( ! extension_loaded( 'memcache' ) ) {
return;
}
$this->interceptMemcacheMethodToSpan( $ctx, 'get' );
$this->interceptMemcacheMethodToSpan( $ctx, 'set' );
$this->interceptMemcacheMethodToSpan( $ctx, 'replace' );
$this->interceptMemcacheMethodToSpan( $ctx, 'add' );
$this->interceptMemcacheMethodToSpan( $ctx, 'delete');
$this->interceptMemcacheMethodToSpan( $ctx, 'increment' );
$this->interceptMemcacheMethodToSpan( $ctx, 'decrement' );
$this->interceptMemcacheMethodToSpan( $ctx, 'flush' );
$this->interceptMemcacheMethodToSpan( $ctx, 'connect' );
$this->interceptMemcacheMethodToSpan( $ctx, 'close' );
$this->interceptMemcacheMethodToSpan( $ctx, 'pconnect' );
}
private function interceptMemcacheMethodToSpan(RegistrationContextInterface $ctx, string $methodName ): void {
$ctx->interceptCallsToInternalMethod(
'Memcache',
$methodName,
/**
* @param ?object $interceptedCallThis
* @param mixed[] $interceptedCallArgs
*
* @return callable
*/
function ( ?object $interceptedCallThis, array $interceptedCallArgs ) use ($methodName): ?callable {
if ( ! $this->util->verifyInstanceOf( 'Memcache', $interceptedCallThis ) ) {
return null;
}
global $wp_object_cache;
if ( count( $interceptedCallArgs ) > 0 ) {
$key = $interceptedCallArgs[0];
if ( defined( 'WP_CACHE_KEY_SALT' ) && WP_CACHE_KEY_SALT ) {
if ( 0 === strpos( $key, WP_CACHE_KEY_SALT ) ) {
$key = substr( $key, strlen( WP_CACHE_KEY_SALT ) + 1 );
}
}
if ( ! empty( $wp_object_cache ) && is_object( $wp_object_cache ) && 'WP_Object_Cache' === get_class( $wp_object_cache ) ) {
if ( null === $this->flush_number && false !== strpos( $key, 'WP_Object_Cache:flush_number_v' ) ) {
$this->flush_number = false;
} elseif ( false === $this->flush_number ) {
$this->flush_number = sprintf( '%d', $wp_object_cache->get_blog_flush_number() );
$key = substr( $key, strlen( $this->flush_number ) + 1 );
} else if ( 0 === strpos( $key, $this->flush_number ) ) {
$key = substr( $key, strlen( $this->flush_number ) + 1 );
}
}
if ( defined( 'WP_CACHE_KEY_SALT' ) && WP_CACHE_KEY_SALT ) {
global $table_prefix;
if ( 0 === strpos( $key, '_:' ) ) {
$key = substr( $key, 2 );
}
if ( strlen( $table_prefix ) > 0 && 0 === strpos( $key, $table_prefix ) ) {
$key = substr( $key, strlen( $table_prefix) + 1 );
}
}
$span = AutoInstrumentationUtil::beginCurrentSpan(
sprintf( 'memcache::%s %s', $methodName, $key ),
'Memcache',
$methodName,
sprintf( '%s (%s)', $key, $interceptedCallArgs[0] )
);
} else {
$span = AutoInstrumentationUtil::beginCurrentSpan(
sprintf( 'memcache::%s', $methodName ),
'Memcache',
$methodName
);
}
return AutoInstrumentationUtil::createInternalFuncPostHookFromEndSpan( $span );
}
);
}
}