The below implementation gives an example of a package written in Typescript and ejs template engine.
It is recommended to use Typescript to build your scope package
. All Ghada Express Profiler scope packages
are built using Typescript.
You can refer to Axios Scope Repo to check how it was implemented and resemble it.
No let's start with the steps for scope package
creation:
mkdir mypackage
cd mypackage
npm init
npm i @ghadautopia/express-profiler on-finished
In your package.json
file, make sure to lock the @ghadautopia/express-profiler
to the version required for your scope to work. If the user installed your scope package
while using a mismatched version of @ghadautopia/express-profiler
, the user will end up with something like the below error
Error: The scope {"name":"axios","hasToolbarSlot":true,"hasPageView":true} is not instance of ProfilerScope
For example, to allow your scope package
to be used with any @ghadautopia/express-profiler
version, in your package.json
the required version for @ghadautopia/express-profiler
should be "*"
. Like the below
"dependencies": {
// ...
"@ghadautopia/express-profiler": "*",
// ...
}
Install template engine which you will use for rendering the scope view page. Here we are installing ejs but you can install your preferred template engine
npm i ejs
📦mypackage
┣ 📂doc
┃ ┗ 📂images
┃ ┃ ┣ 📜my-img1.png
┃ ┃ ┗ 📜my-img2.png
┣ 📂src
┃ ┣ 📜index.ts
┃ ┣ 📜scope.ts
┃ ┗ 📜stream.ts
┣ 📂views
┃ ┣ 📂script
┃ ┃ ┗ 📜index.js
┃ ┣ 📂styles
┃ ┃ ┗ 📜index.css
┃ ┗ 📂template
┃ ┃ ┗ 📜index.ejs
┣ 📜CHANGELOG.md
┣ 📜README.md
┣ 📜package.json
┗ 📜tsconfig.json
Directory Structure Explanation:
dir/file | Eeplanation |
---|---|
doc | contains the resources (e.g. images) used in the README.md file |
src/index.ts | contains modules you need to expose to be used by the project using your package. At least, you need to expose your package scope module which will be added to Ghada Express Profiler config scopes array prop to enable your scope. For example, in Axios scope package, we are exposing the axiosScope and the axiosStreamMiddlware modules. Those modules should be added to Ghada Express Profiler config props scopes and streamMiddlwares respectively |
src/scope.ts | file containing your scope implementation logic |
src/stream.ts | file containing your stream implementation logic. This module is optional. Required in case your scope needs a new stream to log new data |
views | contains views related files. Not required if your scope only renders a toolbar slot |
views/script/index.js | optional JS file contains the javascript which will run in your scopes page view |
views/styles/index.css | optional CSS file contains the CSS styles which will run in your scopes page view |
views/template/index.ejs | file containing your HTML template which will be rendered to display the scope page |
CHANGELOG.md | the changlog file for this package |
README.md | the readme file for this package |
package.json | package.json file |
tsconfig.json | typescript configuration file |
The stream is responsible for logging data that will be used to render your scope components. It's only required if your scope will use data not already logged by other streams.
Each stream should have a unique name. When creating your stream make sure not to collide with other stream names. Check current stream names below:
Stream name (UNIQUE) | Package | Git repo |
---|---|---|
req-res | within profiler | -- |
axios | TBD | here |
mongoose | TBD | here |
The stream implementation should be located in src/stream.ts
. Check Axios stream
The stream is created via createStream
helper function. You can import it from @ghadautopia/express-profiler
import { createStream } from '@ghadautopia/express-profiler';
const myStream = createStream('my-stream-name');
The createStream
will return an instance of ProfilerStream
. You can use the ProfilerStream::persist
method to log the required data at any point of time of the request lifecycle. The persist
method takes 2 arguments:
- The current
Server response
- Object of the data you want to log
VERY IMPORTANT
MAKE SURE TO CLEAN UP AFTER LOGGING THE REQUIRED DATA. YOU CAN DO THIS BY USING THE ON-FINISHED PACKAGE TO DETECT THAT THE RESPONSE
HAS BEEN SENT.
The example below shows how data is being logged by axios stream
. The axiosMiddleware
will be exposed to the package user to use it during instantiating Ghada Express Profiler
in the streamMiddlewares
config array.
In this middleware, we are making use of axios interceptors and persisting
every response generated by axios. Then, we are using the onFinished
method on the Server response
to destroy the interceptor, because at this point we are sure that the Server response
was sent to the client. Finally, we use next()
to let the request pass through.
export const axiosStreamMiddleware: (axios: AxiosInstance) => RequestHandler = (axios: AxiosInstance) => {
return (req, res, next) => {
const intercept = axios.interceptors.response.use(async function (response) {
await axiosStream.presist(res, response);
return response;
}, async function (error) {
await axiosStream.presist(res, { ...error.response, error });
return Promise.reject(error);
});
onFinished(res, () => axios.interceptors.response.eject(intercept));
next();
}
}
The scope mainly responsible for rendering:
- The scope toolbar slot in
Ghada Express Profiler
toolbar (optional)
- The scope pageview (optional)
The scope should be located in src/scope.ts
. Check Axios scope
The scope is created via createScope
helper function. You can import it from @ghadautopia/express-profiler
import { createScope } from '@ghadautopia/express-profiler';
export const myScope = createScope(props);
createScope function props:
prop | type | desctiption |
---|---|---|
name | string | The name of your scope. It will be used in scope url to direct to the scope's page view |
getToolbarSlot | (optional) async (streamsData) => ToolbarSlotData |
|
getPageTab | (optional) async (streamsData) => PageTabData |
|
getPageView | (optional) async (streamsData>, profilerViewsDir: string) => PageViewData |
|
-
Map { 'stream_name' => [ { token: string; // profiler token id stream: string; // stream name time: string; // time of logging (epoch) data: any; // raw logged data } ] }
-
prop type description text string text rendered in the toolbar slot description string (optional) tooltip text when the user hovers over the slot svg string (optional) svg image code as a string color ProfilerColor enum (optional) Background color of the slot -
prop type description svg string (optional) tab svg title string tab text -
prop type description template string string of html tags to render the page view styles string (optional) string of CSS styles used in page view script string (optional) string of JS script used in page view
The below css classes are available. You can use them whenever you want
If you are using ejs
to implement your templates. Then you can benefit from Ghada Express Profiler
mixins below
mixin | description |
---|---|
formatTimestamp | format valid date string |
getReqStartTime | return formatted request start time |
getReqUrl | return the request full url |
getResStatus | return color status of the response default , danger , warning , info or success . Used with classes bg-{{ color }} or color-{{ color }} to style HTML elements |
getScopeUrl | return url for the scope's page view |
In order to use those mixins, you need to pass the profilerViewsDir
paramter (the second argument of the getPageView
function) to your view template. Then you can include any mixin in your template as shown below. check Axios scope
<%- include(`${profilerViewsDir}/mixins/format-timestamp.ejs`) -%>
<%= formatTimestamp(time) %>
<%- include(`${profilerViewsDir}/mixins/get-res-status.ejs`) -%>
<section class="color-<%= getResStatus({ statusCode: res.status }) %>">
<%= res.status %>
</section>
Please add a README.md file to your package. You can refer to Axios scope readme
- createScope: Function to create new scope
- createStream: Function to create new stream
- getTokenFromRes: Function to get the profiler token assigned to server response
- ProfilerError: Class of Profiler error
- ProfilerColor: An enum to identify background color of toolbar slot