Overview

If you are a dApp developer then you probably know retrieving dApp specific logging and infrastructure analytics is one of the most important parts of the development process, but can also be the most painstaking. Especially when there are several sources of providers you may use including different network endpoints and wallet providers. Today we’ll walk through how to use Terminal Logs, a Terminal product for aggregating logs from any RPC endpoint or wallet provider of your choice.

Here’s what your dApp can do with Terminal Logs:
- Surface logs for any RPC endpoint such as Infura
- Surface logs from any injected web3 wallet providers such as MetaMask
- Introduce cloud logging into your Truffle development environment
- Compatible with web3.js and ethers.js
- Filter logs by type, source, timestamp, and others


First we’ll go through how to wrap your web3 provider to surface logs from any static RPC endpoint and then show how to retrieve logs from any web3 injected endpoint. While wrapping your HTTP provider is fairly simple if you already have a working dApp, we thought it would be helpful to demonstrate actually surfacing the logs with some examples. Specifically, we’ll show how to easily get logs from Infura and Metamask directly onto your Terminal account or command line.

Infura or Other RPC endpoints

In your Javascript project, wherever you initialize your Web3 provider, it probably looks something like this:

import Web3 from 'web3';

const web3=new Web3(new Web3.providers.HttpProvider("YOUR_ENDPOINT_URL"));

In order to surface logs from an RPC endpoint, you will have to have web3 and Terminal SDK installed as well as a Terminal account and API key. To install copy the following into your command line. To make and account and generate and API key check out the website here.

npm install @terminal-packages/sdk
npm install web3

Once you have everything installed, you can send the logs to your Terminal Account by simply initializing your endpoint as follows:

import { TerminalHttpProvider, SourceType } from '@terminal-packages/sdk';
import Web3 from 'web3';
const web3 = new Web3(
	new TerminalHttpProvider({
		host: 'https://yourethnodeurl.io', // your network endpoint
		apiKey: 'yourApiKey', // your Terminal account identifier
		source: SourceType.Terminal //source can be anything you choose.
//use the source to filter specific logs later on. 
})
);

If you want to add specific options for your web3 provider such as timeout, headers or withCredentials, simply add them in at the end of your web3 object like this:

import { TerminalHttpProvider } from '@terminal-packages/sdk';
import Web3 from 'web3';
const web3 = new Web3(
	new TerminalHttpProvider({
		host: ‘https://yourethnodeurl.io’,
		apiKey: ‘yourApiKey’
		source: ‘Source name’, // source can be a dynamic string as well
		timeout: 10000,
		headers: [{ name: 'x-custom-header' value: 'example' }],
		withCredentials: true
})
);

Now we’ll dive into an example of actually retrieving these logs from a real project. For this walk through, we wrote two simple dApps to show Terminal logging in action.

For the first example we used an Infura RPC endpoint. To illustrate logging from an Infura endpoint we created a simple script to check the balance of any Ethereum address.

const Web3 = require('web3');
const sdk = require('@terminal-packages/sdk');
const address = '0xab7c74abC0C4d48d1bdad5DCB26153FC8780f83E';
const web3 = new Web3(
	new sdk.TerminalHttpProvider({
		host: "https://mainnet.infura.io/v3/INFURAAPIKEY",
		apiKey: 'TERMINALAPIKEY',
		source: sdk.SourceType.Infura, //can also use a string
	})
);
web3.eth.getBalance(address, (err, wei) => {
	balance = web3.utils.fromWei(wei, 'ether');
	console.log(balance);
})

In order to run this code yourself, you will have to make a Terminal account and retrieve your API key and then make an Infura account and grab a new RPC endpoint. Also feel free to substitute in any address you’d like.

Once you’ve done this, you can simply run the script from your command line using node.js. As soon as you run the script, the logs will get pushed to your Terminal Logging Platform and look something like this:

The value shown at the top is the web3 call made by our program. To see more information about your logs, you can click on the log you are interested in.


All of these logs can also be easily accessed from you command line using the TerminalCLI. For instructions on how to do that check out the Terminal Docs.

MetaMask and Other Web3 Injected Endpoints

Many dApps do not use a static RPC endpoints in their code at all since it's possible to expose all of your application's functionality alongside the web3 provider injected into your browser by wallets like Metamask. It is important to note that logging from MetaMask is a little bit different from most other injected web3 providers. Because MetaMask is the most widely used, we will begin by showing how to surface logs from there. Logging from MetaMask is as easy as dropping the following code snippet into the <head> tag of your webpage. You do not have to install the Terminal SDK for this.

 <script src="https://storage.googleapis.com/terminal-sdk/metamask/latest/metamask-latest.min.js"></script>
  <script type="text/JavaScript">
      window.terminal.sdk.metamask.startLogging({apiKey: 'YOUR_API_KEY', projectId: 'YOUR_PROJECT_ID'});
  </script>

Note that your 'projectId' is the ID for the Terminal project associated with the provider endpoint you are logging from. To demonstrate this in a real environment we decided to make a quick dApp that only consists of a few simple buttons. The first button will perform the same function as the example above for Infura, while the others will interact directly with the MetaMask browser extension. MetaMask requires a front-end page to inject itself into so we built the dApp using React, however this is not required to retrieve logs using Terminal and the process for surfacing them is the same in React or any other front-end framework.‌

Here is our basic App.js file designed with a few buttons. The first to retrieve the balance of an address of your choice using the MetaMask injected provider. ‌The next button enables metamask browser extension to interact with the current webpage. The extension must be enabled for a page can interact with it. once it is clicked, you will have to reload the page in order to use the other buttons. The next one retrieves the address(es) of the current MetaMask account and the last one asks the user to sign some data using the MetaMask extension. The data being signed is trivial in this case as we do not require that any data actually be signed.  Note that to see what these buttons are doing, you will need to open your browser console. In chrome this is usually done either with ‘F12’, or ‘ctrl + shift + j’.

import React from "react";
import logo from "./logo.svg";
import "./App.css";

function App() {
  const getBalanceMM = async () => {
    window.web3.eth.getBalance(
      "0xab7c74abC0C4d48d1bdad5DCB26153FC8780f83E",
      (error, result) => {
        console.log(error);
        console.log(result.toString(10));
      }
    );
  };

  const enableMM = async () => {
    window.ethereum.enable((error, result) => {
      console.log(error);
      console.log(result);
    });
  };

  const getAddress = async () => {
    window.web3.eth.getAccounts((error, result) => {
      console.log(error);
      console.log(result);
    });
  };

  const requestSignature = async () => {
    window.web3.eth.getAccounts((error, result) => {
      window.web3.eth.sign(
        result[0],
        ["SOME DATA TO SIGN"],
        (error, result) => {
          console.log(error);
          console.log(result);
        }
      );
    });
  };

  return (
    <div>
      <button onClick={() => getBalanceMM()}>Test button getBalance</button>
      <button onClick={() => enableMM()}>
        Enable Metamask (hard refresh page after)
      </button>
      <button onClick={() => getAddress()}>Get Current Metamask Address</button>
      <button onClick={() => requestSignature()}>request signature</button>
    </div>
  );
}

export default App;

You can check out the full project on Github. React inherently creates an index.html which defines the <head> tag of your website. Regardless of how you create the front end of your dApp, all you have to do is paste the html script above into your html file like this:

<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://storage.googleapis.com/terminal-sdk/metamask/latest/metamask-latest.min.js"></script>
    <script type="text/JavaScript">
      window.terminal.sdk.metamask.startLogging({apiKey: 'TERMINAL_API_KEY', projectId: "YOUR_PROJECT_ID"});
    </script>

    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="logo192.png" />
   
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>

The dApp built above will look something like this:

Once you have that snippet in your html file, you are all set and the logs will be sent directly to your Terminal Logging Platform as shown below.

Although the injected injected web3 provider might differ based on which wallet a user has installed on their browser, you can still wrap the provider with TerminalSDK and surface logs. This can be extremely useful for developers because it enables you to capture more granular data about which wallets are most common among users of your dApp, what actions users are taking, and more. For other injected web3 providers, simply wrap the initialization of your provider in the following code as in the first example.

import { TerminalHttpProvider, SourceType } from '@terminal-packages/sdk';
import Web3 from 'web3';

const web3 = new Web3(
  new TerminalHttpProvider({
    apiKey: 'yourApiKey',
    // projectId is not required to log but we suggest
    // using it for the best experience
    projectId: 'YOUR_TERMINAL_PROJECT_ID',// source can be a dynamic string
    source: SourceType.Terminal,
    customHttpProvider: window.ethereum
  })
);


Now that you are receiving logs directly to your Terminal account, you can sort through your logs using an array of different filters or have them sent directly to your command line with TerminalCLI. This makes finding whatever you’re looking for as easy as possible.


Be a part of the community by joining our Discord, follow us on Twitter, and Subscribe to our Blog for all the latest updates on products and features. Read our Docs to learn more about getting started with Terminal.