Crear extensiones para Tracy

Tracy es una gran herramienta para depurar su aplicación. A veces, sin embargo, puede querer tener a mano información adicional. Le mostraremos cómo escribir sus propias extensiones para la Tracy Bar y hacer el desarrollo aún más agradable.

  • Crear su propio panel para la Tracy Bar
  • Crear su propia extensión para la Bluescreen

Encontrará un repositorio de extensiones ya hechas para Tracy en Componette.

Extensiones de la Tracy Bar

Crear una nueva extensión para la Tracy Bar es sencillo. Cree un objeto que implemente la interfaz Tracy\IBarPanel, que tiene dos métodos: getTab() y getPanel(). Estos métodos deben devolver el código HTML de la pestaña (una pequeña etiqueta que se muestra directamente en la Bar) y del panel (una ventana emergente que se muestra al pulsar la pestaña). Si getPanel() no devuelve nada, se muestra solo la pestaña. Si getTab() no devuelve nada, no se muestra nada en absoluto y getPanel() no se llama.

class ExamplePanel implements Tracy\IBarPanel
{
	public function getTab()
	{
		return /* ... */;
	}

	public function getPanel()
	{
		return /* ... */;
	}
}

Registro

El registro se hace llamando a Tracy\Debugger::getBar()->addPanel():

Tracy\Debugger::getBar()->addPanel(new ExamplePanel);

Alternativamente puede registrar el panel directamente en la configuración de la aplicación:

tracy:
	bar:
		- ExamplePanel

Código HTML de la pestaña

Debería tener más o menos este aspecto:

<span title="Explanatory tooltip">
	<svg>...</svg>
	<span class="tracy-label">Title</span>
</span>

La imagen debería estar en formato SVG. Si no hace falta un tooltip explicativo, se puede omitir el <span> exterior.

Código HTML del panel

Debería tener más o menos este aspecto:

<h1>Title</h1>

<div class="tracy-inner">
<div class="tracy-inner-container">
	... content ...
</div>
</div>

El título debería ser el mismo que el de la pestaña o contener información adicional.

Tenga presente que una misma extensión se puede registrar varias veces, quizá con ajustes distintos. Por eso, para los estilos no puede usar IDs de CSS, solo clases, preferiblemente con el formato tracy-addons-<NombreDeClase>[-<opcional>]. Añada esa clase al div junto con la clase tracy-inner. Al escribir CSS conviene anteponer a los selectores #tracy-debug .su-clase, porque eso le da a la regla mayor especificidad que a los estilos del reset.

Estilos predeterminados

En el panel, los elementos <a>, <table>, <pre> y <code> tienen estilos predefinidos. Si quiere crear un enlace que oculte y muestre otro elemento, conéctelos con los atributos href e id y la clase tracy-toggle:

<a href="#tracy-addons-ClassName-{$counter}" class="tracy-toggle">Details</a>

<div id="tracy-addons-ClassName-{$counter}">...</div>

Si el estado predeterminado es colapsado, añada la clase tracy-collapsed a ambos elementos.

Use un contador estático para evitar IDs duplicados en una misma página.

Recursos propios

Si su panel necesita su propia hoja de estilos o su propio script, puede hacer que Tracy cargue archivos adicionales junto con los suyos:

Tracy\Debugger::$customCssFiles[] = __DIR__ . '/panel.css';
Tracy\Debugger::$customJsFiles[] = __DIR__ . '/panel.js';

Soporte para agentes de IA

Cuando un agente de IA maneja el navegador, Tracy envía a la consola de JS un resumen en markdown de la Tracy Bar. Los paneles propios pueden aportar su propio markdown añadiendo un método getAgentInfo(): ?string a su implementación de IBarPanel:

class DatabasePanel implements Tracy\IBarPanel
{
	public function getTab(): string { /* ... */ }
	public function getPanel(): string { /* ... */ }

	public function getAgentInfo(): ?string
	{
		return "## Database\n\n- Queries: {$this->count}\n- Total time: {$this->time} ms\n";
	}
}

El markdown devuelto se incluye en el resumen en markdown de la barra. Cuando el método falta o devuelve null, el panel se omite del resumen.

Véase la integración de Tracy con los agentes de IA para el panorama completo.

Extensiones de la Bluescreen

De esta manera puede añadir visualizaciones propias de las excepciones o paneles que aparecerán en la bluescreen.

Una extensión se crea así:

Tracy\Debugger::getBlueScreen()->addPanel(function (?Throwable $e) { // excepción capturada
	return [
		'tab' => '...Title...',
		'panel' => '...HTML panel content...',
	];
});

La función se llama dos veces. Primero se pasa la propia excepción en el parámetro $e (si se produjo alguna) y el panel devuelto se renderiza al principio de la página. Si devuelve null o un array vacío, el panel no se renderiza. Después se llama con $e = null y el panel devuelto se renderiza debajo de la pila de llamadas. Si la función devuelve 'bottom' => true en el array, el panel se renderiza al final del todo.

Además de paneles, con addAction() puede añadir también acciones: enlaces o botones pulsables que aparecen en la cabecera de la página de error junto a los integrados (como search):

Tracy\Debugger::getBlueScreen()->addAction(function (Throwable $e): ?array {
	if ($e instanceof MyException) {
		return [
			'link' => 'https://example.com/help?code=' . $e->getCode(),
			'label' => 'view help',
		];
	}
	return null;
});

El callback recibe la excepción capturada y devuelve un array con las claves link y label, o null si no quiere añadir ninguna acción para esa excepción.

Acción “create file”

Cuando en la página de error pulsa un archivo que todavía no existe, Tracy ofrece crearlo (la acción create file). Puede controlar el contenido inicial de ese archivo registrando un generador:

Tracy\Debugger::getBlueScreen()->addFileGenerator(function (string $file, ?string $class): ?string {
	if (str_ends_with($file, 'Test.php')) {
		return "<?php\n\nclass $class extends Tester\\TestCase\n{\n\t\$END\$\n}\n";
	}
	return null;
});

El callback recibe la ruta del archivo de destino y, cuando se conoce, el nombre de la clase que debería definirse en él. Devuelve el contenido inicial (el token $END$ marca dónde se colocará el cursor y se elimina de la salida), o null para dejar la decisión a otro generador. Los generadores se prueban empezando por el registrado más recientemente; el generador integrado produce un esqueleto de PHP simple.

Fibers y generadores

Si se lanza una excepción mientras un fiber o un generador está suspendido, su pila no forma parte de la pila de llamadas habitual. Tracy muestra automáticamente la pila de los fibers y generadores accesibles desde la excepción, pero uno que se ejecute de forma independiente se quedaría fuera. Puede añadirlo a la BlueScreen a mano:

Tracy\Debugger::getBlueScreen()->addFiber($fiber);