Как создать свой первый плагин OpenReplay
Если вы используете собственную версию OpenReplay (self-hosting), у вас есть дополнительное преимущество — возможность разрабатывать и устанавливать пользовательские плагины. Это позволит вам добавить функциональность и совместимость, которые OpenReplay не предоставляет «из коробки».
На данный момент существует несколько плагинов, разработанных и поддерживаемых командой OpenReplay, например плагин Redux, который позволяет отслеживать изменения состояния, или плагин Fetch, который даёт вам возможность записывать данные Request и Response. Вы можете посмотреть полный список плагинов здесь, если хотите узнать больше.
В этом руководстве вы научитесь создавать собственный плагин. В частности, мы создадим плагин, который отслеживает метод GET в JQuery.
Создание плагина с нуля
Section titled Создание плагина с нуляМы рекомендуем начать с копирования и вставки папки плагина, который делает что-то похожее на то, что вы хотите сделать, — таким образом у вас уже будут готовы вся логика и настроечный код.
При этом, поскольку плагин, который мы собираемся создать здесь, будет вести себя аналогично плагину Fetch, мы продублируем именно этот плагин.
Тем не менее вам всё равно придётся делать такие вещи, как:
- Изменение бэкенда.
- Добавление новых сообщений в протокол сообщений.
- Сборка некоторых сервисов бэкенда из исходного кода.
Поэтому, если вы ещё не проходили процесс сборки OpenReplay из исходного кода, я бы порекомендовал сначала пройти этот процесс с текущей версией OpenReplay, потому что вы будете делать это несколько раз во время тестирования своего нового кода.
Если же, наоборот, эту часть вы уже освоили — читайте дальше!
Что вам нужно для создания нового плагина?
Section titled Что вам нужно для создания нового плагина?Создание нового плагина состоит из трёх частей:
- Сначала вы должны определить тип сообщения, которое ваш плагин будет отправлять на платформу. Это сообщение должно содержать всю телеметрию, которую вы хотите отслеживать.
- Затем вам нужно обновить фронтенд, чтобы создать компонент, способный отображать данные из плагина. В нашем случае мы добавим вкладку в плеере, в которой перечислены все запросы, выполненные с помощью JQuery.
- Наконец, вам также придётся создать сам плагин! Помните, ради этого мы здесь и собрались. Плагин — это единственная часть из всего этого, которую вы можете разрабатывать вне OpenReplay и которую вы будете устанавливать где-то ещё (в вашем приложении).
Обратите внимание, что в остальной части руководства предполагается, что вы сделали форк нашего репозитория на Github и он у вас где-то готов и работает. Если это не так, пожалуйста, сначала ознакомьтесь с разделом о развёртывании в нашей документации.
Шаг 1: Создание нового сообщения
Section titled Шаг 1: Создание нового сообщенияПервое, что нужно сделать, — понять, какие данные вы хотите захватывать и отображать с помощью своего плагина. В нашем случае, поскольку мы создаём нечто для отслеживания GET-запросов, нам следует убедиться, что мы захватываем следующие элементы:
- URL: очевидно, URL запроса
- Response: мы также попытаемся захватить некоторые из ответов
- Status: код статуса, полученный от сервера
Мы также добавим свойство «duration», чтобы отслеживать, сколько времени занимает выполнение запроса и получение данных, и для этого нам понадобится «timestamp» запроса.
Чтобы сделать это, нам нужно изменить файл mob/messages.rb. Это файл на Ruby, но не волнуйтесь, если вы совсем не знаете Ruby — всё, что вам нужно сделать, это добавить новую запись, описывающую ваше новое сообщение, что-то вроде этого:
message 112, 'JQueryGET' do
string 'Method'
string 'url'
string 'response'
string 'status'
string 'duration'
int 'timestamp'
end
Обратите внимание, что я также определил:
- ID сообщения (112) — это случайное число, которое ещё не используется (вы можете посмотреть на другие сообщения в файле) и которое меньше 200.
- Имя сообщения — это полностью на ваше усмотрение, просто убедитесь, что оно описывает ваш тип сообщения.
- Поле «method» — таким образом мы потенциально могли бы повторно использовать это сообщение для других методов в будущем.
- Типы свойств как “string” и “int” — это потому, что наш кодировщик превратит массивы и объекты в строки.
После того как это сделано, вам нужно убедиться, что сообщение доступно отовсюду, поэтому вы запустите 2 скрипта внутри этой папки:
$ ruby run.rb
$ sh format.sh
Как только это завершится, сообщение и его ID будут реплицированы и добавлены везде на бэкенде, где это необходимо.
Теперь перейдём к фронтенду и посмотрим, что нам нужно изменить.
Шаг 2: Обновление фронтенда
Section titled Шаг 2: Обновление фронтендаКогда сообщение готово, вам нужно обновить функцию messageDistributor (внутри файла frontend/app/player/MessageDistributor/MessageDistributor.ts), которая получает все сообщения и решает, что с ними делать.
Внутри функции вы увидите большую конструкцию switch и уже добавленный новый case для вашего сообщения (вы заметите, что используемое имя записано в другом регистре, чем тот, который использовали вы). В случае этого примера для типа сообщения «JQueryGET» вы получите тип «j_query_get».
Теперь вам нужно добавить сообщение в список — компоненты фронтенда будут использовать эти списки. Вы сделаете это с помощью функции listAppend.
Case должен выглядеть так:
case 'j_query_get':
listAppend("jquery", Resource({
method: msg.method,
url: msg.url,
payload: {},
response: msg.response,
status: msg.status,
type: TYPES.JQUERY,
time: msg.timestamp - this.sessionStart,
duration: msg.duration,
index
}))
break;
Теперь есть несколько вещей, которые мы должны сделать, чтобы это заработало:
- Нам нужно добавить список «jquery», для этого мы изменим файл
frontend/app/player/lists/index.jsи добавим «jquery» в массивentityNamesWithRed. - Нам нужно добавить
TYPES.JQUERY, что можно сделать, изменив этот файл:frontend/app/types/session/resource.js
После этого мы создадим сам компонент, отображающий данные внутри плеера. Что-то вроде этого:

Чтобы сделать это, мы будем опираться на существующий компонент и скопируем компонент Fetch. Для этого мы продублируем папку frontend/app/components/Session_/Fetch и назовём её «JQuery».
Мы обновим каждую ссылку на fetch внутри только что созданной папки, чтобы убедиться, что везде значится “jquery” (здесь, вероятно, имеет смысл воспользоваться функцией «Найти и заменить»).
Это создаст компонент визуализации, который затем нужно будет добавить вручную. Сначала вам нужно отредактировать файл frontend/app/components/Session_/Player/Controls/Controls.js, чтобы добавить кнопку «JQuery» в правом нижнем углу экрана, где отображаются все элементы управления.
Найдите код JSX и добавьте блок, подобный этому:
{showJQuery && (
<ControlButton
disabled={disabled && !inspectorMode}
onClick={() => toggleBottomTools(JQUERY)}
active={bottomBlock === JQUERY && !inspectorMode}
hasErrors={jqueryRedCount > 0}
count={jqueryCount}
label="JQUERY"
noIcon
labelClassName="!text-base font-semibold"
containerClassName="mx-2"
/>
)}
Пока вы этим занимаетесь, убедитесь, что вы определили все соответствующие переменные, такие как showJQuery, jqueryCount, JQUERY и jqueryRedCount. Если вы не уверены, как это сделать, поищите их аналоги для fetch — вы быстро их найдёте.
После добавления кнопки вы теперь можете отредактировать файл frontend/app/components/Session_/Player/Player.js и добавить сам компонент.
Чтобы сделать это, после его импорта убедитесь, что вы добавили блок, подобный следующему, внутри секции JSX:
{ bottomBlock === JQUERY &&
<JQuery />
}
В рамках этого вам также придётся добавить константу JQUERY для экспорта из файла frontend/app/duck/components/player.js.
Это позаботится обо всём.
Теперь ваш фронтенд готов отображать информацию, нам нужно найти способ её генерировать. Так что давайте посмотрим на сам код плагина!
Шаг 3: Создание вашего плагина
Section titled Шаг 3: Создание вашего плагинаВы можете создать этот проект где угодно. Смысл в том, чтобы предоставить устанавливаемый пакет для использования в других проектах.
Поэтому убедитесь, что файл package.json выглядит так:
{
"name": "tracker-jquery",
"version": "1.0.0",
"description": "jquery openreplay tracker",
"main": "src/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"peerDependencies": {
"@openreplay/tracker": ">=3.6.0"
},
"devDependencies": {
"@openreplay/tracker": "<latest version of the tracker>",
"prettier": "^1.18.2",
"replace-in-files-cli": "^1.0.0"
}
}
И мы добавим файл index.js внутрь папки src проекта. Вы вольны структурировать этот проект так, как считаете нужным, при условии, что ваши экспортируемые функции соответствуют определённым заранее заданным критериям.
Анатомия плагина проста: вы определяете функцию, которая при вызове возвращает новую функцию, ожидающую, что ей будет передан атрибут app. Этот атрибут app содержит экземпляр трекера. Внутри возвращаемой функции вы вольны делать всё, что хотите, при условии, что вы отправляете сообщение через объект app. Это сообщение будет получено платформой и обработано в соответствии с набором правил.
Формат сообщения будет тем, который мы определили в начале этого руководства.
Позвольте мне показать вам, как выглядит код нашего плагина JQuery:
import { App, Messages } from '@openreplay/tracker';
export default function($) {
const oldGET = $.get;
return (app) => {
const newGET = async (settingsObj) => {
const startTime = performance.now();
let resp = await fetch(settingsObj.url, {
method: 'GET'
})
const duration = performance.now() - startTime;
let valueResp = null;
if(settingsObj.json) {
valueResp = await resp.json()
} else {
valueResp = await resp.text()
}
const getStj = (res) => {
let r = {...res}
if (r && typeof r.body !== 'string') {
try {
r.body = JSON.stringify(r.body)
} catch {
r.body = "<unable to stringify>"
}
}
return JSON.stringify(r)
}
const msg = Messages.JQueryGET(
'GET',
String(settingsObj.url),
getStj(resp),
resp.status,
duration,
(new Date()).getTime()
)
console.log("Sending a message to the tracker....", msg)
app.send(msg, true)
return valueResp;
}
$.get = newGET;
}
}
По сути, всё, что я делаю, — это заменяю метод .get из JQuery на пользовательский, который на самом деле использует fetch за кулисами (это совершенно необязательно, вы могли бы использовать и метод GET из JQuery). И после того как все запросы выполнены, код отправляет сообщение, используя метод app.send. Сообщение создаётся с помощью метода Messages.JQueryGET, который был создан для нас Ruby-скриптом ранее.
Атрибуты, которые получает это сообщение, — это, очевидно, те, которые мы определили как структуру самого сообщения на Шаге 1. И, что самое важное, все они обязательны: если вам приходится иметь дело с пустым значением, то передавайте пустой массив/объект/строку/что угодно, но никогда не пропускайте ключ.
Публикация плагина
Section titled Публикация плагинаКогда вы закончите локальное тестирование и будете уверены, что плагин готов, вам нужно будет опубликовать его в NPM.
Следуйте этому руководству, чтобы понять, как это сделать: https://docs.npmjs.com/creating-and-publishing-unscoped-public-packages
Тестирование плагина
Section titled Тестирование плагинаПосле публикации вы захотите использовать свой плагин повсюду. Механика использования плагинов с трекером OpenReplay всегда одинакова.
- Сначала вам нужно создать экземпляр трекера.
- Затем вам нужно вызвать метод
useи передать ему функцию, полученную в результате вызова вашего плагина. - Наконец, запустите трекер с помощью метода
start.
Вот пример кода того, как выглядит использование этого плагина внутри приложения React:
import logo from './logo.svg';
import './App.css';
import tracker from 'openreplay-tracker'
import jqueryTracker from 'tracker-jquery'
import { useEffect } from 'react';
import $ from 'jquery'
const t = new tracker({
__DISABLE_SECURE_MODE: true, //only if you're testing locally
ingestPoint: "openreplay.<your custom domain>/ingest",
projectKey: "<your project key>",
})
function App() {
useEffect(()=> {
t.use(jqueryTracker($))
t.start()
async function doGet() {
let resp = await $.get({
url: "http://localhost:3000"
})
console.log(resp)
}
doGet()
}, [])
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
Код выполняет GET-запрос с использованием метода get из Jquery после загрузки страницы, и поскольку мы настроили наш маленький хитроумный трекер, мы фактически можем отслеживать этот запрос.
Вот как должен выглядеть конечный результат у вас:

Вы можете ознакомиться с этим репозиторием, чтобы получить полный исходный код этого руководства.
Если у вас возникнут какие-либо проблемы с любым из шагов этого процесса, пожалуйста, свяжитесь с нами в нашем сообществе в Slack и задайте вопрос нашим разработчикам напрямую!