You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by ke...@apache.org on 2020/12/19 11:59:02 UTC

[skywalking-nodejs] branch rel/0.1.0 created (now 6ee09b4)

This is an automated email from the ASF dual-hosted git repository.

kezhenxu94 pushed a change to branch rel/0.1.0
in repository https://gitbox.apache.org/repos/asf/skywalking-nodejs.git.


      at 6ee09b4  Finalize 0.1.0

This branch includes the following new commits:

     new 6ee09b4  Finalize 0.1.0

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[skywalking-nodejs] 01/01: Finalize 0.1.0

Posted by ke...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kezhenxu94 pushed a commit to branch rel/0.1.0
in repository https://gitbox.apache.org/repos/asf/skywalking-nodejs.git

commit 6ee09b47214dcc3e4c548a2afc3426a0e40038e0
Author: kezhenxu94 <ke...@apache.org>
AuthorDate: Sat Dec 19 19:58:29 2020 +0800

    Finalize 0.1.0
    
    - Complete missing plugin tests.
    - Fix bug of `startTime` and `endTime`.
    - Fix bug that some env vars not work.
---
 .../common/Dockerfile.agent => .editorconfig       |  22 +-
 README.md                                          |  14 +-
 package-lock.json                                  | 518 +++++++++++++++++++++
 package.json                                       |   4 +
 src/agent/Buffer.ts                                |  31 +-
 src/agent/protocol/Protocol.ts                     |   4 +-
 src/agent/protocol/grpc/GrpcProtocol.ts            |  20 +-
 src/agent/protocol/grpc/clients/HeartbeatClient.ts |  24 +-
 .../protocol/grpc/clients/TraceReportClient.ts     |  42 +-
 src/core/PluginInstaller.ts                        |  59 ++-
 src/index.ts                                       |   9 +-
 .../protocol/Protocol.ts => lib/EventEmitter.ts}   |  17 +-
 src/plugins/AxiosPlugin.ts                         |  18 +-
 src/plugins/ExpressPlugin.ts                       |  28 +-
 src/plugins/HttpPlugin.ts                          |  96 ++--
 src/trace/Component.ts                             |  13 +-
 src/trace/context/ContextManager.ts                |  57 ++-
 src/trace/context/SpanContext.ts                   |  28 +-
 src/trace/span/EntrySpan.ts                        |   4 +-
 src/trace/span/StackedSpan.ts                      |   4 -
 tests/plugins/{http => axios}/client.ts            |  16 +-
 tests/plugins/{http => axios}/docker-compose.yml   |  10 +-
 tests/plugins/{http => axios}/expected.data.yaml   |  99 ++--
 tests/plugins/{http => axios}/server.ts            |  16 +-
 tests/plugins/{http => axios}/test.ts              |   6 +-
 tests/plugins/common/Dockerfile.agent              |   1 -
 tests/plugins/common/base-compose.yml              |   1 -
 tests/plugins/{http => express}/client.ts          |  23 +-
 tests/plugins/{http => express}/docker-compose.yml |  10 +-
 tests/plugins/{http => express}/expected.data.yaml |  97 ++--
 tests/plugins/{http => express}/server.ts          |  23 +-
 tests/plugins/{http => express}/test.ts            |   6 +-
 tests/plugins/http/client.ts                       |  16 +-
 tests/plugins/http/docker-compose.yml              |   2 -
 tests/plugins/http/expected.data.yaml              |  87 ++--
 tests/plugins/http/server.ts                       |  16 +-
 tests/plugins/http/test.ts                         |   4 +-
 37 files changed, 1022 insertions(+), 423 deletions(-)

diff --git a/tests/plugins/common/Dockerfile.agent b/.editorconfig
similarity index 82%
copy from tests/plugins/common/Dockerfile.agent
copy to .editorconfig
index 4c51529..9e8ec25 100644
--- a/tests/plugins/common/Dockerfile.agent
+++ b/.editorconfig
@@ -1,3 +1,4 @@
+#
 # Licensed to the Apache Software Foundation (ASF) under one or more
 # contributor license agreements.  See the NOTICE file distributed with
 # this work for additional information regarding copyright ownership.
@@ -12,16 +13,15 @@
 # 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.
+#
 
-ARG SW_NODE_VERSION
-
-FROM node:${SW_NODE_VERSION}
-
-ARG ROOT=.
-
-WORKDIR /app
-
-ADD $ROOT /app
-
-RUN npm install request && npm install
+root = true
 
+[*]
+charset = utf-8
+indent_style = space
+indent_size = 2
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+quote_type = single
diff --git a/README.md b/README.md
index dfb635f..d2eab71 100644
--- a/README.md
+++ b/README.md
@@ -15,12 +15,12 @@ microservices, cloud native and container-based (Docker, Kubernetes, Mesos) arch
 
 ## Set up NodeJS Agent
 
-SkyWalking NodeJS SDK requires SkyWalking 8.0+.
+SkyWalking NodeJS SDK requires SkyWalking backend (OAP) 8.0+ and NodeJS >= 10.
 
 ```typescript
-import Agent from 'skywalking';
+import agent from 'skywalking';
 
-Agent.start({
+agent.start({
   serviceName: '',
   serviceInstance: '',
   collectorAddress: '',
@@ -38,15 +38,19 @@ Environment Variable | Description | Default
 | `SW_AGENT_COLLECTOR_BACKEND_SERVICES` | The backend OAP server address | `127.0.0.1:11800` |
 | `SW_AGENT_AUTHENTICATION` | The authentication token to verify that the agent is trusted by the backend OAP, as for how to configure the backend, refer to [the yaml](https://github.com/apache/skywalking/blob/4f0f39ffccdc9b41049903cc540b8904f7c9728e/oap-server/server-bootstrap/src/main/resources/application.yml#L155-L158). | not set |
 | `SW_AGENT_LOGGING_LEVEL` | The logging level, could be one of `CRITICAL`, `FATAL`, `ERROR`, `WARN`(`WARNING`), `INFO`, `DEBUG` | `INFO` |
+| `SW_IGNORE_SUFFIX` | The suffices of endpoints that will be ignored (not traced), comma separated | `.jpg,.jpeg,.js,.css,.png,.bmp,.gif,.ico,.mp3,.mp4,.html,.svg` |
+| `SW_TRACE_IGNORE_PATH` | The paths of endpoints that will be ignored (not traced), comma separated | `` |
 | `SW_AGENT_MAX_BUFFER_SIZE` | The maximum buffer size before sending the segment data to backend | `'1000'` |
 
 ## Supported Libraries
 
-There're some built-in plugins that support automatic instrumentation of NodeJS libraries, the complete lists are as follows:
+There are some built-in plugins that support automatic instrumentation of NodeJS libraries, the complete lists are as follows:
 
 Library | Plugin Name
 | :--- | :--- |
-| built-in `http` module | `sw_http` |
+| built-in `http` and `https` module | `http` |
+| [`express`](https://expressjs.com) | `express` |
+| [`axios`](https://github.com/axios/axios) | `axios` |
 
 ## License
 Apache 2.0
diff --git a/package-lock.json b/package-lock.json
index dbc294d..2592ba0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1045,6 +1045,16 @@
         "@babel/types": "^7.3.0"
       }
     },
+    "@types/body-parser": {
+      "version": "1.19.0",
+      "resolved": "https://registry.npm.taobao.org/@types/body-parser/download/@types/body-parser-1.19.0.tgz?cache=0&sync_timestamp=1605052521338&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fbody-parser%2Fdownload%2F%40types%2Fbody-parser-1.19.0.tgz",
+      "integrity": "sha1-BoWzxH6zAG/+0RfN1VFkth+AU48=",
+      "dev": true,
+      "requires": {
+        "@types/connect": "*",
+        "@types/node": "*"
+      }
+    },
     "@types/bytebuffer": {
       "version": "5.0.41",
       "resolved": "https://registry.npmjs.org/@types/bytebuffer/-/bytebuffer-5.0.41.tgz",
@@ -1060,6 +1070,15 @@
       "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
       "dev": true
     },
+    "@types/connect": {
+      "version": "3.4.34",
+      "resolved": "https://registry.npm.taobao.org/@types/connect/download/@types/connect-3.4.34.tgz?cache=0&sync_timestamp=1607458722751&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fconnect%2Fdownload%2F%40types%2Fconnect-3.4.34.tgz",
+      "integrity": "sha1-FwpAIjptZmAG2TyhKK8r6x2bGQE=",
+      "dev": true,
+      "requires": {
+        "@types/node": "*"
+      }
+    },
     "@types/dockerode": {
       "version": "2.5.34",
       "resolved": "https://registry.npm.taobao.org/@types/dockerode/download/@types/dockerode-2.5.34.tgz",
@@ -1069,6 +1088,29 @@
         "@types/node": "*"
       }
     },
+    "@types/express": {
+      "version": "4.17.9",
+      "resolved": "https://registry.npm.taobao.org/@types/express/download/@types/express-4.17.9.tgz?cache=0&sync_timestamp=1605057477768&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fexpress%2Fdownload%2F%40types%2Fexpress-4.17.9.tgz",
+      "integrity": "sha1-9fLfat1wP/KEKK3VK97IoQkbCng=",
+      "dev": true,
+      "requires": {
+        "@types/body-parser": "*",
+        "@types/express-serve-static-core": "*",
+        "@types/qs": "*",
+        "@types/serve-static": "*"
+      }
+    },
+    "@types/express-serve-static-core": {
+      "version": "4.17.17",
+      "resolved": "https://registry.npm.taobao.org/@types/express-serve-static-core/download/@types/express-serve-static-core-4.17.17.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fexpress-serve-static-core%2Fdownload%2F%40types%2Fexpress-serve-static-core-4.17.17.tgz",
+      "integrity": "sha1-a6AkZRZbbJw9jbOije9rFvybcPU=",
+      "dev": true,
+      "requires": {
+        "@types/node": "*",
+        "@types/qs": "*",
+        "@types/range-parser": "*"
+      }
+    },
     "@types/google-protobuf": {
       "version": "3.7.2",
       "resolved": "https://registry.npmjs.org/@types/google-protobuf/-/google-protobuf-3.7.2.tgz",
@@ -1129,6 +1171,12 @@
       "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz",
       "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w=="
     },
+    "@types/mime": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npm.taobao.org/@types/mime/download/@types/mime-2.0.3.tgz",
+      "integrity": "sha1-yJO3NyHbc2mZQ7/DZTsd63+qSjo=",
+      "dev": true
+    },
     "@types/node": {
       "version": "14.0.13",
       "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.13.tgz",
@@ -1140,12 +1188,33 @@
       "integrity": "sha1-5IbQ2XOW15vu3QpuM/RTT/a0lz4=",
       "dev": true
     },
+    "@types/on-finished": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/@types/on-finished/-/on-finished-2.3.1.tgz",
+      "integrity": "sha512-mzVYaYcFs5Jd2n/O6uYIRUsFRR1cHyZLRvkLCU0E7+G5WhY0qBDAR5fUCeZbvecYOSh9ikhlesyi2UfI8B9ckQ==",
+      "dev": true,
+      "requires": {
+        "@types/node": "*"
+      }
+    },
     "@types/prettier": {
       "version": "2.1.5",
       "resolved": "https://registry.npm.taobao.org/@types/prettier/download/@types/prettier-2.1.5.tgz",
       "integrity": "sha1-tqs7uinha4IdhOCez63tRiuBawA=",
       "dev": true
     },
+    "@types/qs": {
+      "version": "6.9.5",
+      "resolved": "https://registry.npm.taobao.org/@types/qs/download/@types/qs-6.9.5.tgz?cache=0&sync_timestamp=1605055106687&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fqs%2Fdownload%2F%40types%2Fqs-6.9.5.tgz",
+      "integrity": "sha1-Q0cRvdSete5p2QwdZ8NUqajssYs=",
+      "dev": true
+    },
+    "@types/range-parser": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npm.taobao.org/@types/range-parser/download/@types/range-parser-1.2.3.tgz?cache=0&sync_timestamp=1605055243791&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Frange-parser%2Fdownload%2F%40types%2Frange-parser-1.2.3.tgz",
+      "integrity": "sha1-fuMwunyq+5gJC+zoal7kQRWQTCw=",
+      "dev": true
+    },
     "@types/semver": {
       "version": "7.2.0",
       "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.2.0.tgz",
@@ -1155,6 +1224,16 @@
         "@types/node": "*"
       }
     },
+    "@types/serve-static": {
+      "version": "1.13.8",
+      "resolved": "https://registry.npm.taobao.org/@types/serve-static/download/@types/serve-static-1.13.8.tgz?cache=0&sync_timestamp=1605657655340&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fserve-static%2Fdownload%2F%40types%2Fserve-static-1.13.8.tgz",
+      "integrity": "sha1-hREp1DRDPHCCFIV0/+wmPVgwnEY=",
+      "dev": true,
+      "requires": {
+        "@types/mime": "*",
+        "@types/node": "*"
+      }
+    },
     "@types/ssh2": {
       "version": "0.5.45",
       "resolved": "https://registry.npm.taobao.org/@types/ssh2/download/@types/ssh2-0.5.45.tgz?cache=0&sync_timestamp=1605057226497&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fssh2%2Fdownload%2F%40types%2Fssh2-0.5.45.tgz",
@@ -1212,6 +1291,16 @@
       "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
       "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
     },
+    "accepts": {
+      "version": "1.3.7",
+      "resolved": "https://registry.npm.taobao.org/accepts/download/accepts-1.3.7.tgz",
+      "integrity": "sha1-UxvHJlF6OytB+FACHGzBXqq1B80=",
+      "dev": true,
+      "requires": {
+        "mime-types": "~2.1.24",
+        "negotiator": "0.6.2"
+      }
+    },
     "acorn": {
       "version": "7.4.1",
       "resolved": "https://registry.npm.taobao.org/acorn/download/acorn-7.4.1.tgz",
@@ -1604,6 +1693,12 @@
       "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
       "dev": true
     },
+    "array-flatten": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npm.taobao.org/array-flatten/download/array-flatten-1.1.1.tgz",
+      "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=",
+      "dev": true
+    },
     "array-sort": {
       "version": "0.1.4",
       "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-0.1.4.tgz",
@@ -1842,6 +1937,47 @@
         "tweetnacl": "^0.14.3"
       }
     },
+    "body-parser": {
+      "version": "1.19.0",
+      "resolved": "https://registry.npm.taobao.org/body-parser/download/body-parser-1.19.0.tgz",
+      "integrity": "sha1-lrJwnlfJxOCab9Zqj9l5hE9p8Io=",
+      "dev": true,
+      "requires": {
+        "bytes": "3.1.0",
+        "content-type": "~1.0.4",
+        "debug": "2.6.9",
+        "depd": "~1.1.2",
+        "http-errors": "1.7.2",
+        "iconv-lite": "0.4.24",
+        "on-finished": "~2.3.0",
+        "qs": "6.7.0",
+        "raw-body": "2.4.0",
+        "type-is": "~1.6.17"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz?cache=0&sync_timestamp=1607566551397&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-2.6.9.tgz",
+          "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz?cache=0&sync_timestamp=1607433856030&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "dev": true
+        },
+        "qs": {
+          "version": "6.7.0",
+          "resolved": "https://registry.npm.taobao.org/qs/download/qs-6.7.0.tgz",
+          "integrity": "sha1-QdwaAV49WB8WIXdr4xr7KHapsbw=",
+          "dev": true
+        }
+      }
+    },
     "brace-expansion": {
       "version": "1.1.11",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -1929,6 +2065,12 @@
         "long": "~3"
       }
     },
+    "bytes": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npm.taobao.org/bytes/download/bytes-3.1.0.tgz",
+      "integrity": "sha1-9s95M6Ng4FiPqf3oVlHNx/gF0fY=",
+      "dev": true
+    },
     "cache-base": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
@@ -2203,6 +2345,21 @@
       "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
       "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
     },
+    "content-disposition": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npm.taobao.org/content-disposition/download/content-disposition-0.5.3.tgz",
+      "integrity": "sha1-4TDK9+cnkIfFYWwgB9BIVpiYT70=",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "5.1.2"
+      }
+    },
+    "content-type": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npm.taobao.org/content-type/download/content-type-1.0.4.tgz",
+      "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=",
+      "dev": true
+    },
     "convert-source-map": {
       "version": "1.7.0",
       "resolved": "https://registry.npm.taobao.org/convert-source-map/download/convert-source-map-1.7.0.tgz",
@@ -2212,6 +2369,18 @@
         "safe-buffer": "~5.1.1"
       }
     },
+    "cookie": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npm.taobao.org/cookie/download/cookie-0.4.0.tgz",
+      "integrity": "sha1-vrQ35wIrO21JAZ0IhmUwPr6cFLo=",
+      "dev": true
+    },
+    "cookie-signature": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npm.taobao.org/cookie-signature/download/cookie-signature-1.0.6.tgz",
+      "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=",
+      "dev": true
+    },
     "copy-descriptor": {
       "version": "0.1.1",
       "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
@@ -2455,6 +2624,18 @@
       "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
       "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
     },
+    "depd": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npm.taobao.org/depd/download/depd-1.1.2.tgz",
+      "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
+      "dev": true
+    },
+    "destroy": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npm.taobao.org/destroy/download/destroy-1.0.4.tgz",
+      "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=",
+      "dev": true
+    },
     "detect-libc": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
@@ -2579,6 +2760,11 @@
         "safer-buffer": "^2.1.0"
       }
     },
+    "ee-first": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz",
+      "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+    },
     "emittery": {
       "version": "0.7.2",
       "resolved": "https://registry.npm.taobao.org/emittery/download/emittery-0.7.2.tgz",
@@ -2599,6 +2785,12 @@
         "env-variable": "0.0.x"
       }
     },
+    "encodeurl": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npm.taobao.org/encodeurl/download/encodeurl-1.0.2.tgz",
+      "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
+      "dev": true
+    },
     "end-of-stream": {
       "version": "1.4.4",
       "resolved": "https://registry.npm.taobao.org/end-of-stream/download/end-of-stream-1.4.4.tgz",
@@ -2642,6 +2834,12 @@
       "integrity": "sha1-Ck2uN9YA0VopukU9jvkg8YRDM/Y=",
       "dev": true
     },
+    "escape-html": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npm.taobao.org/escape-html/download/escape-html-1.0.3.tgz",
+      "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=",
+      "dev": true
+    },
     "escape-string-regexp": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
@@ -2679,6 +2877,12 @@
       "integrity": "sha1-dNLrTeC42hKTcRkQ1Qd1ubcQ72Q=",
       "dev": true
     },
+    "etag": {
+      "version": "1.8.1",
+      "resolved": "https://registry.npm.taobao.org/etag/download/etag-1.8.1.tgz",
+      "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
+      "dev": true
+    },
     "exec-sh": {
       "version": "0.3.4",
       "resolved": "https://registry.npm.taobao.org/exec-sh/download/exec-sh-0.3.4.tgz",
@@ -2761,6 +2965,67 @@
         "jest-regex-util": "^26.0.0"
       }
     },
+    "express": {
+      "version": "4.17.1",
+      "resolved": "https://registry.npm.taobao.org/express/download/express-4.17.1.tgz",
+      "integrity": "sha1-RJH8OGBc9R+GKdOcK10Cb5ikwTQ=",
+      "dev": true,
+      "requires": {
+        "accepts": "~1.3.7",
+        "array-flatten": "1.1.1",
+        "body-parser": "1.19.0",
+        "content-disposition": "0.5.3",
+        "content-type": "~1.0.4",
+        "cookie": "0.4.0",
+        "cookie-signature": "1.0.6",
+        "debug": "2.6.9",
+        "depd": "~1.1.2",
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "etag": "~1.8.1",
+        "finalhandler": "~1.1.2",
+        "fresh": "0.5.2",
+        "merge-descriptors": "1.0.1",
+        "methods": "~1.1.2",
+        "on-finished": "~2.3.0",
+        "parseurl": "~1.3.3",
+        "path-to-regexp": "0.1.7",
+        "proxy-addr": "~2.0.5",
+        "qs": "6.7.0",
+        "range-parser": "~1.2.1",
+        "safe-buffer": "5.1.2",
+        "send": "0.17.1",
+        "serve-static": "1.14.1",
+        "setprototypeof": "1.1.1",
+        "statuses": "~1.5.0",
+        "type-is": "~1.6.18",
+        "utils-merge": "1.0.1",
+        "vary": "~1.1.2"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz?cache=0&sync_timestamp=1607566551397&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-2.6.9.tgz",
+          "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz?cache=0&sync_timestamp=1607433856030&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "dev": true
+        },
+        "qs": {
+          "version": "6.7.0",
+          "resolved": "https://registry.npm.taobao.org/qs/download/qs-6.7.0.tgz",
+          "integrity": "sha1-QdwaAV49WB8WIXdr4xr7KHapsbw=",
+          "dev": true
+        }
+      }
+    },
     "extend": {
       "version": "3.0.2",
       "resolved": "https://registry.npm.taobao.org/extend/download/extend-3.0.2.tgz",
@@ -2884,6 +3149,38 @@
         }
       }
     },
+    "finalhandler": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npm.taobao.org/finalhandler/download/finalhandler-1.1.2.tgz",
+      "integrity": "sha1-t+fQAP/RGTjQ/bBTUG9uur6fWH0=",
+      "dev": true,
+      "requires": {
+        "debug": "2.6.9",
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "on-finished": "~2.3.0",
+        "parseurl": "~1.3.3",
+        "statuses": "~1.5.0",
+        "unpipe": "~1.0.0"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz?cache=0&sync_timestamp=1607566551397&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-2.6.9.tgz",
+          "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz?cache=0&sync_timestamp=1607433856030&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "dev": true
+        }
+      }
+    },
     "find-up": {
       "version": "4.1.0",
       "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
@@ -2932,6 +3229,12 @@
         "mime-types": "^2.1.12"
       }
     },
+    "forwarded": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npm.taobao.org/forwarded/download/forwarded-0.1.2.tgz",
+      "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=",
+      "dev": true
+    },
     "fragment-cache": {
       "version": "0.2.1",
       "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
@@ -2941,6 +3244,12 @@
         "map-cache": "^0.2.2"
       }
     },
+    "fresh": {
+      "version": "0.5.2",
+      "resolved": "https://registry.npm.taobao.org/fresh/download/fresh-0.5.2.tgz",
+      "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=",
+      "dev": true
+    },
     "fs-constants": {
       "version": "1.0.0",
       "resolved": "https://registry.npm.taobao.org/fs-constants/download/fs-constants-1.0.0.tgz",
@@ -3489,6 +3798,27 @@
         "kind-of": "^6.0.0"
       }
     },
+    "http-errors": {
+      "version": "1.7.2",
+      "resolved": "https://registry.npm.taobao.org/http-errors/download/http-errors-1.7.2.tgz?cache=0&sync_timestamp=1593407611415&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhttp-errors%2Fdownload%2Fhttp-errors-1.7.2.tgz",
+      "integrity": "sha1-T1ApzxMjnzEDblsuVSkrz7zIXI8=",
+      "dev": true,
+      "requires": {
+        "depd": "~1.1.2",
+        "inherits": "2.0.3",
+        "setprototypeof": "1.1.1",
+        "statuses": ">= 1.5.0 < 2",
+        "toidentifier": "1.0.0"
+      },
+      "dependencies": {
+        "inherits": {
+          "version": "2.0.3",
+          "resolved": "https://registry.npm.taobao.org/inherits/download/inherits-2.0.3.tgz",
+          "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+          "dev": true
+        }
+      }
+    },
     "http-signature": {
       "version": "1.2.0",
       "resolved": "https://registry.npm.taobao.org/http-signature/download/http-signature-1.2.0.tgz?cache=0&sync_timestamp=1600868532049&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhttp-signature%2Fdownload%2Fhttp-signature-1.2.0.tgz",
@@ -3580,6 +3910,12 @@
       "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=",
       "dev": true
     },
+    "ipaddr.js": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npm.taobao.org/ipaddr.js/download/ipaddr.js-1.9.1.tgz",
+      "integrity": "sha1-v/OFQ+64mEglB5/zoqjmy9RngbM=",
+      "dev": true
+    },
     "is-accessor-descriptor": {
       "version": "0.1.6",
       "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
@@ -5489,12 +5825,30 @@
         "object-visit": "^1.0.0"
       }
     },
+    "media-typer": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npm.taobao.org/media-typer/download/media-typer-0.3.0.tgz",
+      "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
+      "dev": true
+    },
+    "merge-descriptors": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npm.taobao.org/merge-descriptors/download/merge-descriptors-1.0.1.tgz",
+      "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=",
+      "dev": true
+    },
     "merge-stream": {
       "version": "2.0.0",
       "resolved": "https://registry.npm.taobao.org/merge-stream/download/merge-stream-2.0.0.tgz",
       "integrity": "sha1-UoI2KaFN0AyXcPtq1H3GMQ8sH2A=",
       "dev": true
     },
+    "methods": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npm.taobao.org/methods/download/methods-1.1.2.tgz",
+      "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=",
+      "dev": true
+    },
     "micromatch": {
       "version": "3.1.10",
       "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
@@ -5576,6 +5930,12 @@
         }
       }
     },
+    "mime": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npm.taobao.org/mime/download/mime-1.6.0.tgz",
+      "integrity": "sha1-Ms2eXGRVO9WNGaVor0Uqz/BJgbE=",
+      "dev": true
+    },
     "mime-db": {
       "version": "1.44.0",
       "resolved": "https://registry.npm.taobao.org/mime-db/download/mime-db-1.44.0.tgz?cache=0&sync_timestamp=1600831159918&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmime-db%2Fdownload%2Fmime-db-1.44.0.tgz",
@@ -5773,6 +6133,12 @@
         "sax": "^1.2.4"
       }
     },
+    "negotiator": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npm.taobao.org/negotiator/download/negotiator-0.6.2.tgz",
+      "integrity": "sha1-/qz3zPUlp3rpY0Q2pkiD/+yjRvs=",
+      "dev": true
+    },
     "neo-async": {
       "version": "2.6.1",
       "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz",
@@ -5994,6 +6360,14 @@
         "isobject": "^3.0.1"
       }
     },
+    "on-finished": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+      "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+      "requires": {
+        "ee-first": "1.1.1"
+      }
+    },
     "once": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -6116,6 +6490,12 @@
       "integrity": "sha1-9o5OW6GFKsLK3AD0VV//bCq7YXg=",
       "dev": true
     },
+    "parseurl": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npm.taobao.org/parseurl/download/parseurl-1.3.3.tgz",
+      "integrity": "sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ=",
+      "dev": true
+    },
     "pascalcase": {
       "version": "0.1.1",
       "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
@@ -6145,6 +6525,12 @@
       "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
       "dev": true
     },
+    "path-to-regexp": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npm.taobao.org/path-to-regexp/download/path-to-regexp-0.1.7.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpath-to-regexp%2Fdownload%2Fpath-to-regexp-0.1.7.tgz",
+      "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=",
+      "dev": true
+    },
     "performance-now": {
       "version": "2.1.0",
       "resolved": "https://registry.npm.taobao.org/performance-now/download/performance-now-2.1.0.tgz",
@@ -6239,6 +6625,16 @@
         "yargs": "^3.10.0"
       }
     },
+    "proxy-addr": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npm.taobao.org/proxy-addr/download/proxy-addr-2.0.6.tgz",
+      "integrity": "sha1-/cIzZQVEfT8vLGOO0nLK9hS7sr8=",
+      "dev": true,
+      "requires": {
+        "forwarded": "~0.1.2",
+        "ipaddr.js": "1.9.1"
+      }
+    },
     "psl": {
       "version": "1.8.0",
       "resolved": "https://registry.npm.taobao.org/psl/download/psl-1.8.0.tgz",
@@ -6267,6 +6663,24 @@
       "integrity": "sha1-yzroBuh0BERYTvFUzo7pjUA/PjY=",
       "dev": true
     },
+    "range-parser": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npm.taobao.org/range-parser/download/range-parser-1.2.1.tgz",
+      "integrity": "sha1-PPNwI9GZ4cJNGlW4SADC8+ZGgDE=",
+      "dev": true
+    },
+    "raw-body": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npm.taobao.org/raw-body/download/raw-body-2.4.0.tgz",
+      "integrity": "sha1-oc5vucm8NWylLoklarWQWeE9AzI=",
+      "dev": true,
+      "requires": {
+        "bytes": "3.1.0",
+        "http-errors": "1.7.2",
+        "iconv-lite": "0.4.24",
+        "unpipe": "1.0.0"
+      }
+    },
     "rc": {
       "version": "1.2.8",
       "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
@@ -6640,6 +7054,64 @@
       "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
       "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ=="
     },
+    "send": {
+      "version": "0.17.1",
+      "resolved": "https://registry.npm.taobao.org/send/download/send-0.17.1.tgz",
+      "integrity": "sha1-wdiwWfeQD3Rm3Uk4vcROEd2zdsg=",
+      "dev": true,
+      "requires": {
+        "debug": "2.6.9",
+        "depd": "~1.1.2",
+        "destroy": "~1.0.4",
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "etag": "~1.8.1",
+        "fresh": "0.5.2",
+        "http-errors": "~1.7.2",
+        "mime": "1.6.0",
+        "ms": "2.1.1",
+        "on-finished": "~2.3.0",
+        "range-parser": "~1.2.1",
+        "statuses": "~1.5.0"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz?cache=0&sync_timestamp=1607566551397&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-2.6.9.tgz",
+          "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          },
+          "dependencies": {
+            "ms": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz?cache=0&sync_timestamp=1607433856030&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.0.0.tgz",
+              "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+              "dev": true
+            }
+          }
+        },
+        "ms": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.1.tgz?cache=0&sync_timestamp=1607433856030&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.1.1.tgz",
+          "integrity": "sha1-MKWGTrPrsKZvLr5tcnrwagnYbgo=",
+          "dev": true
+        }
+      }
+    },
+    "serve-static": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npm.taobao.org/serve-static/download/serve-static-1.14.1.tgz",
+      "integrity": "sha1-Zm5jbcTwEPfvKZcKiKZ0MgiYsvk=",
+      "dev": true,
+      "requires": {
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "parseurl": "~1.3.3",
+        "send": "0.17.1"
+      }
+    },
     "set-blocking": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
@@ -6666,6 +7138,12 @@
         "split-string": "^3.0.1"
       }
     },
+    "setprototypeof": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.1.1.tgz",
+      "integrity": "sha1-fpWsskqpL1iF4KvvW6ExMw1K5oM=",
+      "dev": true
+    },
     "shebang-command": {
       "version": "1.2.0",
       "resolved": "https://registry.npm.taobao.org/shebang-command/download/shebang-command-1.2.0.tgz",
@@ -6991,6 +7469,12 @@
         }
       }
     },
+    "statuses": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npm.taobao.org/statuses/download/statuses-1.5.0.tgz",
+      "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
+      "dev": true
+    },
     "stealthy-require": {
       "version": "1.1.1",
       "resolved": "https://registry.npm.taobao.org/stealthy-require/download/stealthy-require-1.1.1.tgz",
@@ -7423,6 +7907,12 @@
         }
       }
     },
+    "toidentifier": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npm.taobao.org/toidentifier/download/toidentifier-1.0.0.tgz",
+      "integrity": "sha1-fhvjRw8ed5SLxD2Uo8j013UrpVM=",
+      "dev": true
+    },
     "tough-cookie": {
       "version": "3.0.1",
       "resolved": "https://registry.npm.taobao.org/tough-cookie/download/tough-cookie-3.0.1.tgz",
@@ -7614,6 +8104,16 @@
       "integrity": "sha1-CeJJ696FHTseSNJ8EFREZn8XuD0=",
       "dev": true
     },
+    "type-is": {
+      "version": "1.6.18",
+      "resolved": "https://registry.npm.taobao.org/type-is/download/type-is-1.6.18.tgz",
+      "integrity": "sha1-TlUs0F3wlGfcvE73Od6J8s83wTE=",
+      "dev": true,
+      "requires": {
+        "media-typer": "0.3.0",
+        "mime-types": "~2.1.24"
+      }
+    },
     "typedarray-to-buffer": {
       "version": "3.1.5",
       "resolved": "https://registry.npm.taobao.org/typedarray-to-buffer/download/typedarray-to-buffer-3.1.5.tgz",
@@ -7671,6 +8171,12 @@
         "set-value": "^2.0.1"
       }
     },
+    "unpipe": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npm.taobao.org/unpipe/download/unpipe-1.0.0.tgz",
+      "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
+      "dev": true
+    },
     "unset-value": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
@@ -7737,6 +8243,12 @@
       "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
       "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
     },
+    "utils-merge": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npm.taobao.org/utils-merge/download/utils-merge-1.0.1.tgz",
+      "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
+      "dev": true
+    },
     "uuid": {
       "version": "8.1.0",
       "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.1.0.tgz",
@@ -7771,6 +8283,12 @@
         "spdx-expression-parse": "^3.0.0"
       }
     },
+    "vary": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npm.taobao.org/vary/download/vary-1.1.2.tgz",
+      "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
+      "dev": true
+    },
     "verror": {
       "version": "1.10.0",
       "resolved": "https://registry.npm.taobao.org/verror/download/verror-1.10.0.tgz",
diff --git a/package.json b/package.json
index 458bbef..d45c00e 100644
--- a/package.json
+++ b/package.json
@@ -35,12 +35,15 @@
     "email": "dev@skywalking.apache.org"
   },
   "devDependencies": {
+    "@types/express": "^4.17.9",
     "@types/google-protobuf": "^3.7.2",
     "@types/jest": "^26.0.15",
     "@types/node": "^14.0.11",
+    "@types/on-finished": "^2.3.1",
     "@types/semver": "^7.2.0",
     "@types/uuid": "^8.0.0",
     "axios": "^0.21.0",
+    "express": "^4.17.1",
     "grpc-tools": "^1.10.0",
     "grpc_tools_node_protoc_ts": "^4.0.0",
     "jest": "^26.6.3",
@@ -57,6 +60,7 @@
   "dependencies": {
     "google-protobuf": "^3.12.2",
     "grpc": "^1.10.1",
+    "on-finished": "^2.3.0",
     "semver": "^7.3.2",
     "tslib": "^2.0.3",
     "uuid": "^8.1.0",
diff --git a/src/agent/Buffer.ts b/src/agent/Buffer.ts
index 8f4f061..99a18fb 100644
--- a/src/agent/Buffer.ts
+++ b/src/agent/Buffer.ts
@@ -18,18 +18,16 @@
  */
 
 import { createLogger } from '../logging';
-import Segment from '../trace/context/Segment';
 import config from '../config/AgentConfig';
-import TraceReportClient from '../agent/protocol/grpc/clients/TraceReportClient';
 
 const logger = createLogger(__filename);
 
-class Buffer {
-  maxSize: number;
-  buffer: Segment[];
+export default class Buffer<T> {
+  private readonly maxSize: number;
+  private readonly buffer: T[];
 
-  constructor(maxSize: number = 1000) {
-    this.maxSize = maxSize;
+  constructor() {
+    this.maxSize = config.maxBufferSize;
     this.buffer = [];
   }
 
@@ -37,16 +35,17 @@ class Buffer {
     return this.buffer.length;
   }
 
-  put(segment: Segment): this {
-    if (this.buffer.length > this.maxSize) {
-      logger.warn('Drop the data because of the buffer is oversized');
-      return this;
+  put(element: T): boolean {
+    if (this.length > this.maxSize) {
+      logger.warn('Drop the data because of the buffer is oversize');
+      return false;
     }
-    this.buffer.push(segment);
-    TraceReportClient.ref();  // this is currently hard-coded for grpc, if other protocols added need to change
+    this.buffer.push(element);
 
-    return this;
+    return true;
   }
-}
 
-export default new Buffer(config.maxBufferSize);
+  take(): T {
+    return this.buffer.splice(0, 1)[0];
+  }
+}
diff --git a/src/agent/protocol/Protocol.ts b/src/agent/protocol/Protocol.ts
index 7f87c6d..778437e 100644
--- a/src/agent/protocol/Protocol.ts
+++ b/src/agent/protocol/Protocol.ts
@@ -23,7 +23,7 @@
 export default interface Protocol {
   isConnected: boolean;
 
-  heartbeat(): void;
+  heartbeat(): this;
 
-  report(): void;
+  report(): this;
 }
diff --git a/src/agent/protocol/grpc/GrpcProtocol.ts b/src/agent/protocol/grpc/GrpcProtocol.ts
index 4875459..df0bc1f 100644
--- a/src/agent/protocol/grpc/GrpcProtocol.ts
+++ b/src/agent/protocol/grpc/GrpcProtocol.ts
@@ -22,15 +22,25 @@ import HeartbeatClient from '../../../agent/protocol/grpc/clients/HeartbeatClien
 import TraceReportClient from '../../../agent/protocol/grpc/clients/TraceReportClient';
 
 export default class GrpcProtocol implements Protocol {
+  private readonly heartbeatClient: HeartbeatClient;
+  private readonly traceReportClient: TraceReportClient;
+
+  constructor() {
+    this.heartbeatClient = new HeartbeatClient();
+    this.traceReportClient = new TraceReportClient();
+  }
+
   get isConnected(): boolean {
-    return HeartbeatClient.isConnected && TraceReportClient.isConnected;
+    return this.heartbeatClient.isConnected && this.traceReportClient.isConnected;
   }
 
-  heartbeat() {
-    HeartbeatClient.start();
+  heartbeat(): this {
+    this.heartbeatClient.start();
+    return this;
   }
 
-  report() {
-    TraceReportClient.start();
+  report(): this {
+    this.traceReportClient.start();
+    return this;
   }
 }
diff --git a/src/agent/protocol/grpc/clients/HeartbeatClient.ts b/src/agent/protocol/grpc/clients/HeartbeatClient.ts
index bd36b7a..660d620 100755
--- a/src/agent/protocol/grpc/clients/HeartbeatClient.ts
+++ b/src/agent/protocol/grpc/clients/HeartbeatClient.ts
@@ -32,19 +32,21 @@ import * as os from 'os';
 
 const logger = createLogger(__filename);
 
-class HeartbeatClient implements Client {
-  heartbeatClient?: ManagementServiceClient;
-  heartbeatTimer?: NodeJS.Timeout;
+export default class HeartbeatClient implements Client {
+  private readonly managementServiceClient: ManagementServiceClient;
+  private heartbeatTimer?: NodeJS.Timeout;
+
+  constructor() {
+    this.managementServiceClient = new ManagementServiceClient(config.collectorAddress, grpc.credentials.createInsecure(), {
+      interceptors: [AuthInterceptor],
+    });
+  }
 
   get isConnected(): boolean {
-    return this.heartbeatClient?.getChannel().getConnectivityState(true) === connectivityState.READY;
+    return this.managementServiceClient.getChannel().getConnectivityState(true) === connectivityState.READY;
   }
 
   start() {
-    this.heartbeatClient = new ManagementServiceClient(config.collectorAddress, grpc.credentials.createInsecure(), {
-      interceptors: [AuthInterceptor],
-    });
-
     if (this.heartbeatTimer) {
       logger.warn(`
         The heartbeat timer has already been scheduled,
@@ -69,7 +71,7 @@ class HeartbeatClient implements Client {
     ]);
 
     this.heartbeatTimer = setInterval(() => {
-      this.heartbeatClient?.reportInstanceProperties(
+      this.managementServiceClient.reportInstanceProperties(
         instanceProperties,
 
         (error, _) => {
@@ -78,7 +80,7 @@ class HeartbeatClient implements Client {
           }
         },
       );
-      this.heartbeatClient?.keepAlive(
+      this.managementServiceClient.keepAlive(
         keepAlivePkg,
 
         (error, _) => {
@@ -90,5 +92,3 @@ class HeartbeatClient implements Client {
     }, 20000).unref();
   }
 }
-
-export default new HeartbeatClient();
diff --git a/src/agent/protocol/grpc/clients/TraceReportClient.ts b/src/agent/protocol/grpc/clients/TraceReportClient.ts
index 9a18032..fcc7fd8 100755
--- a/src/agent/protocol/grpc/clients/TraceReportClient.ts
+++ b/src/agent/protocol/grpc/clients/TraceReportClient.ts
@@ -24,32 +24,40 @@ import { createLogger } from '../../../../logging';
 import Client from './Client';
 import { TraceSegmentReportServiceClient } from '../../../../proto/language-agent/Tracing_grpc_pb';
 import AuthInterceptor from '../AuthInterceptor';
-import buffer from '../../../../agent/Buffer';
+import Buffer from '../../../../agent/Buffer';
 import SegmentObjectAdapter from '../SegmentObjectAdapter';
+import { emitter } from '../../../../lib/EventEmitter';
+import Segment from '../../../../trace/context/Segment';
 
 const logger = createLogger(__filename);
 
-class TraceReportClient implements Client {
-  reporterClient?: TraceSegmentReportServiceClient;
-  timeout: any;
+export default class TraceReportClient implements Client {
+  private readonly reporterClient: TraceSegmentReportServiceClient;
+  private readonly buffer: Buffer<Segment>;
+  private timeout?: NodeJS.Timeout;
 
-  get isConnected(): boolean {
-    return this.reporterClient?.getChannel().getConnectivityState(true) === connectivityState.READY;
-  }
-
-  ref() {
-    this.timeout.ref();
-  }
-
-  start() {
+  constructor() {
+    this.buffer = new Buffer();
     this.reporterClient = new TraceSegmentReportServiceClient(
       config.collectorAddress,
       grpc.credentials.createInsecure(),
       { interceptors: [AuthInterceptor] },
     );
+    emitter.on('segment-finished', (segment) => {
+      if (this.buffer.put(segment)) {
+        this.timeout?.ref();
+      }
+    });
+  }
+
+  get isConnected(): boolean {
+    return this.reporterClient?.getChannel().getConnectivityState(true) === connectivityState.READY;
+  }
+
+  start() {
     const reportFunction = () => {
       try {
-        if (buffer.length === 0 || !this.reporterClient) {
+        if (this.buffer.length === 0) {
           return;
         }
 
@@ -59,8 +67,8 @@ class TraceReportClient implements Client {
           }
         });
 
-        while (buffer.length > 0) {
-          const segment = buffer.buffer.splice(0, 1)[0];
+        while (this.buffer.length > 0) {
+          const segment = this.buffer.take();
           if (segment) {
             if (logger.isDebugEnabled()) {
               logger.debug('Sending segment ', { segment });
@@ -79,5 +87,3 @@ class TraceReportClient implements Client {
     this.timeout = setTimeout(reportFunction, 1000).unref();
   }
 }
-
-export default new TraceReportClient();
diff --git a/src/core/PluginInstaller.ts b/src/core/PluginInstaller.ts
index 80ce569..e959501 100644
--- a/src/core/PluginInstaller.ts
+++ b/src/core/PluginInstaller.ts
@@ -26,12 +26,14 @@ import * as semver from 'semver';
 const logger = createLogger(__filename);
 
 let topModule = module;
-for (; topModule.parent; topModule = topModule.parent);
+while (topModule.parent) {
+  topModule = topModule.parent;
+}
 
-class PluginInstaller {
-  pluginDir: string;
-  require: (name: string) => any = topModule.require.bind(topModule);
-  resolve = (request: string) => (module.constructor as any)._resolveFilename(request, topModule);
+export default class PluginInstaller {
+  private readonly pluginDir: string;
+  private readonly require: (name: string) => any = topModule.require.bind(topModule);
+  private readonly resolve = (request: string) => (module.constructor as any)._resolveFilename(request, topModule);
 
   constructor() {
     this.pluginDir = path.resolve(__dirname, '..', 'plugins');
@@ -72,33 +74,30 @@ class PluginInstaller {
 
   install(): void {
     fs.readdirSync(this.pluginDir)
-      .filter((file) => !(file.endsWith('.d.ts') || file.endsWith('.js.map')))
-      .forEach((file) => {
-        let plugin;
-        const pluginFile = path.join(this.pluginDir, file);
-
-        try {
-          plugin = require(pluginFile).default as SwPlugin;
-          const { isSupported, version } = this.checkModuleVersion(plugin);
-
-          if (!isSupported) {
-            logger.info(`Plugin ${plugin.module} ${version} doesn't satisfy the supported version ${plugin.versions}`);
-            return;
-          }
-
-          logger.info(`Installing plugin ${plugin.module} ${plugin.versions}`);
+    .filter((file) => !(file.endsWith('.d.ts') || file.endsWith('.js.map')))
+    .forEach((file) => {
+      let plugin;
+      const pluginFile = path.join(this.pluginDir, file);
+
+      try {
+        plugin = require(pluginFile).default as SwPlugin;
+        const { isSupported, version } = this.checkModuleVersion(plugin);
+
+        if (!isSupported) {
+          logger.info(`Plugin ${plugin.module} ${version} doesn't satisfy the supported version ${plugin.versions}`);
+          return;
+        }
 
-          plugin.install();
+        logger.info(`Installing plugin ${plugin.module} ${plugin.versions}`);
 
-        } catch (e) {
-          if (plugin) {
-            logger.error(`Error installing plugin ${plugin.module} ${plugin.versions}`);
-          } else {
-            logger.error(`Error processing plugin ${pluginFile}`);
-          }
+        plugin.install();
+      } catch (e) {
+        if (plugin) {
+          logger.error(`Error installing plugin ${plugin.module} ${plugin.versions}`);
+        } else {
+          logger.error(`Error processing plugin ${pluginFile}`);
         }
-      });
+      }
+    });
   }
 }
-
-export default new PluginInstaller();
diff --git a/src/index.ts b/src/index.ts
index 698e22e..1dfae71 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -20,14 +20,12 @@
 import config, { AgentConfig, finalizeConfig } from './config/AgentConfig';
 import GrpcProtocol from './agent/protocol/grpc/GrpcProtocol';
 import { createLogger } from './logging';
-import Protocol from './agent/protocol/Protocol';
 import PluginInstaller from './core/PluginInstaller';
 
 const logger = createLogger(__filename);
 
 class Agent {
-  started = false;
-  protocol: Protocol = new GrpcProtocol();
+  private started = false;
 
   start(options: AgentConfig = {}): void {
     if (process.env.SW_DISABLE === 'true') {
@@ -45,10 +43,9 @@ class Agent {
 
     this.started = true;
 
-    PluginInstaller.install();
+    new PluginInstaller().install();
 
-    this.protocol.heartbeat();
-    this.protocol.report();
+    new GrpcProtocol().heartbeat().report();
   }
 }
 
diff --git a/src/agent/protocol/Protocol.ts b/src/lib/EventEmitter.ts
similarity index 68%
copy from src/agent/protocol/Protocol.ts
copy to src/lib/EventEmitter.ts
index 7f87c6d..9d4f708 100644
--- a/src/agent/protocol/Protocol.ts
+++ b/src/lib/EventEmitter.ts
@@ -17,13 +17,16 @@
  *
  */
 
-/**
- * The transport protocol between the agent and the backend (OAP).
- */
-export default interface Protocol {
-  isConnected: boolean;
+/* tslint:disable:unified-signatures */
+
+import { EventEmitter } from 'events';
+import Segment from '../trace/context/Segment';
 
-  heartbeat(): void;
+declare interface SkyWalkingEventEmitter {
+  on(event: 'segment-finished', listener: (segment: Segment) => void): this;
+}
 
-  report(): void;
+class SkyWalkingEventEmitter extends EventEmitter {
 }
+
+export const emitter: SkyWalkingEventEmitter = new SkyWalkingEventEmitter();
diff --git a/src/plugins/AxiosPlugin.ts b/src/plugins/AxiosPlugin.ts
index 37e330c..1ce7191 100644
--- a/src/plugins/AxiosPlugin.ts
+++ b/src/plugins/AxiosPlugin.ts
@@ -25,14 +25,13 @@ import Span from '../trace/span/Span';
 import Tag from '../Tag';
 import { SpanLayer } from '../proto/language-agent/Tracing_pb';
 import { createLogger } from '../logging';
-import PluginInstaller from '../core/PluginInstaller';
 
 const logger = createLogger(__filename);
 
 class AxiosPlugin implements SwPlugin {
   readonly module = 'axios';
   readonly versions = '*';
-  axios = PluginInstaller.require('axios').default;
+  axios = require('axios').default;
 
   install(): void {
     if (logger.isDebugEnabled()) {
@@ -53,7 +52,7 @@ class AxiosPlugin implements SwPlugin {
       }
 
       span.stop();
-    }
+    };
 
     this.axios.interceptors.request.use(
       (config: any) => {
@@ -71,7 +70,7 @@ class AxiosPlugin implements SwPlugin {
         error.config.span.stop();
 
         return Promise.reject(error);
-      }
+      },
     );
 
     this.axios.interceptors.response.use(
@@ -87,26 +86,23 @@ class AxiosPlugin implements SwPlugin {
         copyStatusAndStop(error.config.span, error.response);
 
         return Promise.reject(error);
-      }
+      },
     );
 
     const _request = this.axios.Axios.prototype.request;
 
-    this.axios.Axios.prototype.request = function (config: any) {
+    this.axios.Axios.prototype.request = function(config: any) {
       const { host, pathname: operation } = new URL(config.url);  // TODO: this may throw invalid URL
       const span = ContextManager.current.newExitSpan(operation, host).start();
 
       try {
-        span.component = Component.HTTP;  // TODO: add Component.AXIOS (to main Skywalking project)
+        span.component = Component.AXIOS;  // TODO: add Component.AXIOS (to main Skywalking project)
         span.layer = SpanLayer.HTTP;
         span.peer = host;
         span.tag(Tag.httpURL(host + operation));
         span.async();
 
-        const request = _request.call(this, {...config, span});
-
-        return request;
-
+        return _request.call(this, { ...config, span });
       } catch (e) {
         span.error(e);
         span.stop();
diff --git a/src/plugins/ExpressPlugin.ts b/src/plugins/ExpressPlugin.ts
index 1cd3172..2ca1e8a 100644
--- a/src/plugins/ExpressPlugin.ts
+++ b/src/plugins/ExpressPlugin.ts
@@ -24,25 +24,18 @@ import { Component } from '../trace/Component';
 import Tag from '../Tag';
 import { SpanLayer } from '../proto/language-agent/Tracing_pb';
 import { ContextCarrier } from '../trace/context/ContextCarrier';
-import { createLogger } from '../logging';
-import PluginInstaller from '../core/PluginInstaller';
-
-const logger = createLogger(__filename);
+import onFinished from 'on-finished';
 
 class ExpressPlugin implements SwPlugin {
   readonly module = 'express';
   readonly versions = '*';
 
   install(): void {
-    if (logger.isDebugEnabled()) {
-      logger.debug('installing express plugin');
-    }
     this.interceptServerRequest();
   }
 
   private interceptServerRequest() {
-    const onFinished = PluginInstaller.require('on-finished');
-    const router = PluginInstaller.require('express/lib/router');
+    const router = require('express/lib/router');
     const _handle = router.handle;
 
     router.handle = function(req: IncomingMessage, res: ServerResponse, out: any) {
@@ -58,13 +51,16 @@ class ExpressPlugin implements SwPlugin {
       const span = ContextManager.current.newEntrySpan(operation, carrier).start();
 
       let stopped = 0;
-      const stopIfNotStopped = () => {
+      const stopIfNotStopped = (err: Error | null) => {
         if (!stopped++) {
           span.stop();
           span.tag(Tag.httpStatusCode(res.statusCode));
           if (res.statusCode && res.statusCode >= 400) {
             span.errored = true;
           }
+          if (err) {
+            span.error(err);
+          }
           if (res.statusMessage) {
             span.tag(Tag.httpStatusMsg(res.statusMessage));
           }
@@ -78,21 +74,19 @@ class ExpressPlugin implements SwPlugin {
         span.tag(Tag.httpURL(span.peer + req.url));
 
         const ret = _handle.call(this, req, res, (err: Error) => {
-          if (err)
+          if (err) {
             span.error(err);
-          else
+          } else {
             span.errored = true;
+          }
           out.call(this, err);
           stopped -= 1;  // skip first stop attempt, make sure stop executes once status code and message is set
-          onFinished(req, stopIfNotStopped);  // this must run after any handlers deferred in 'out'
         });
-        onFinished(req, stopIfNotStopped);
+        onFinished(res, stopIfNotStopped); // this must run after any handlers deferred in 'out'
 
         return ret;
-
       } catch (e) {
-        span.error(e);
-        stopIfNotStopped();
+        stopIfNotStopped(e);
         throw e;
       }
     };
diff --git a/src/plugins/HttpPlugin.ts b/src/plugins/HttpPlugin.ts
index 2984cc5..5c2d8b2 100644
--- a/src/plugins/HttpPlugin.ts
+++ b/src/plugins/HttpPlugin.ts
@@ -26,19 +26,13 @@ import Tag from '../Tag';
 import ExitSpan from '../trace/span/ExitSpan';
 import { SpanLayer } from '../proto/language-agent/Tracing_pb';
 import { ContextCarrier } from '../trace/context/ContextCarrier';
-import { createLogger } from '../logging';
-
-const logger = createLogger(__filename);
+import onFinished from 'on-finished';
 
 class HttpPlugin implements SwPlugin {
   readonly module = 'http';
   readonly versions = '*';
 
   install(): void {
-    if (logger.isDebugEnabled()) {
-      logger.debug('installing http plugin');
-    }
-
     const http = require('http');
     const https = require('https');
 
@@ -51,7 +45,7 @@ class HttpPlugin implements SwPlugin {
   private interceptClientRequest(module: any) {
     const _request = module.request;
 
-    module.request = function () {
+    module.request = function() {
       const url: URL | string | RequestOptions = arguments[0];
 
       const { host, pathname } =
@@ -60,16 +54,26 @@ class HttpPlugin implements SwPlugin {
           : typeof url === 'string'
           ? new URL(url)  // TODO: this may throw invalid URL
           : {
-              host: (url.host || url.hostname || 'unknown') + ':' + url.port,
-              pathname: url.path || '/',
-            };
+            host: (url.host || url.hostname || 'unknown') + ':' + (url.port || 80),
+            pathname: url.path || '/',
+          };
       const operation = pathname.replace(/\?.*$/g, '');
 
-      let stopped = 0;  // compensating if request aborted right after creation 'close' is not emitted
-      const stopIfNotStopped = () => !stopped++ ? span.stop() : null;  // make sure we stop only once
       const span: ExitSpan = ContextManager.current.newExitSpan(operation, host).start() as ExitSpan;
 
+      let stopped = 0;  // compensating if request aborted right after creation 'close' is not emitted
+      const stopIfNotStopped = (err?: Error | null) => {
+        if (stopped++) {
+          return;
+        }
+        span.stop();
+        if (err) {
+          span.error(err);
+        }
+      };
+
       try {
+        // TODO: these should go into span class
         if (span.depth === 1) {  // only set HTTP if this span is not overridden by a higher level one
           span.component = Component.HTTP;
           span.layer = SpanLayer.HTTP;
@@ -82,17 +86,13 @@ class HttpPlugin implements SwPlugin {
           span.tag(Tag.httpURL(httpURL));
         }
 
-        const request: ClientRequest = _request.apply(this, arguments);
+        const req: ClientRequest = _request.apply(this, arguments);
 
         span.inject().items.forEach((item) => {
-          request.setHeader(item.key, item.value);
+          req.setHeader(item.key, item.value);
         });
 
-        request.on('close', stopIfNotStopped);
-        request.on('abort', () => (span.errored = true, stopIfNotStopped()));
-        request.on('error', (err) => (span.error(err), stopIfNotStopped()));
-
-        request.prependListener('response', (res) => {
+        req.prependListener('response', (res) => {
           span.resync();
           span.tag(Tag.httpStatusCode(res.statusCode));
           if (res.statusCode && res.statusCode >= 400) {
@@ -101,19 +101,15 @@ class HttpPlugin implements SwPlugin {
           if (res.statusMessage) {
             span.tag(Tag.httpStatusMsg(res.statusMessage));
           }
-          stopIfNotStopped();
         });
+        onFinished(req, stopIfNotStopped);
 
         span.async();
 
-        return request;
+        return req;
 
       } catch (e) {
-        if (!stopped) {  // don't want to set error if exception occurs after clean close
-          span.error(e);
-          stopIfNotStopped();
-        }
-
+        stopIfNotStopped(e);
         throw e;
       }
     };
@@ -122,7 +118,7 @@ class HttpPlugin implements SwPlugin {
   private interceptServerRequest(module: any) {
     const _emit = module.Server.prototype.emit;
 
-    module.Server.prototype.emit = function () {
+    module.Server.prototype.emit = function() {
       if (arguments[0] !== 'request') {
         return _emit.apply(this, arguments);
       }
@@ -138,27 +134,37 @@ class HttpPlugin implements SwPlugin {
 
       const carrier = ContextCarrier.from(headersMap);
       const operation = (req.url || '/').replace(/\?.*/g, '');
-      const span = ContextManager.current.newEntrySpan(operation, carrier);
+      const span = ContextManager.current.newEntrySpan(operation, carrier).start();
 
-      return ContextManager.withSpan(span, (self, args) => {
-        span.component = Component.HTTP_SERVER;
-        span.layer = SpanLayer.HTTP;
-        span.peer = req.headers.host || '';
-        span.tag(Tag.httpURL(span.peer + req.url));
+      span.component = Component.HTTP_SERVER;
+      span.layer = SpanLayer.HTTP;
+      span.peer = req.headers.host || '';
+      span.tag(Tag.httpURL(span.peer + req.url));
 
-        const ret = _emit.apply(self, args);
-
-        span.tag(Tag.httpStatusCode(res.statusCode));
-        if (res.statusCode && res.statusCode >= 400) {
-          span.errored = true;
-        }
-        if (res.statusMessage) {
-          span.tag(Tag.httpStatusMsg(res.statusMessage));
+      let stopped = 0;
+      const stopIfNotStopped = (err: Error | null) => {
+        if (!stopped++) {
+          span.stop();
+          span.tag(Tag.httpStatusCode(res.statusCode));
+          if (res.statusCode && res.statusCode >= 400) {
+            span.errored = true;
+          }
+          if (err) {
+            span.error(err);
+          }
+          if (res.statusMessage) {
+            span.tag(Tag.httpStatusMsg(res.statusMessage));
+          }
         }
+      };
+      onFinished(res, stopIfNotStopped);
 
-        return ret;
-
-      }, this, arguments);
+      try {
+        return _emit.apply(this, arguments);
+      } catch (e) {
+        stopIfNotStopped(e);
+        throw e;
+      }
     };
   }
 }
diff --git a/src/trace/Component.ts b/src/trace/Component.ts
index 60c4c5d..1eb9597 100644
--- a/src/trace/Component.ts
+++ b/src/trace/Component.ts
@@ -18,11 +18,12 @@
  */
 
 export class Component {
-  static UNKNOWN = new Component(0);
-  static HTTP = new Component(2);
-  static MONGODB = new Component(9);
-  static HTTP_SERVER = new Component(49);
-  static EXPRESS = new Component(4002);
+  static readonly UNKNOWN = new Component(0);
+  static readonly HTTP = new Component(2);
+  static readonly MONGODB = new Component(9);
+  static readonly HTTP_SERVER = new Component(49);
+  static readonly EXPRESS = new Component(4002);
+  static readonly AXIOS = new Component(4005);
 
-  constructor(public id: number) {}
+  constructor(public readonly id: number) {}
 }
diff --git a/src/trace/context/ContextManager.ts b/src/trace/context/ContextManager.ts
index 3ed253e..a586856 100644
--- a/src/trace/context/ContextManager.ts
+++ b/src/trace/context/ContextManager.ts
@@ -21,26 +21,38 @@ import Context from '../../trace/context/Context';
 import Span from '../../trace/span/Span';
 import SpanContext from '../../trace/context/SpanContext';
 
-type AsyncState = {context: Context, spans: Span[]};
+import async_hooks from 'async_hooks';
 
-const async_hooks = require('async_hooks');
-let   store: any;
+type AsyncState = { context: Context, spans: Span[] };
+
+let store: {
+  getStore(): AsyncState | undefined;
+  enterWith(s: AsyncState): void;
+};
 
 if (async_hooks.AsyncLocalStorage) {
   store = new async_hooks.AsyncLocalStorage();
-
 } else {  // Node 10 doesn't have AsyncLocalStore, so recreate it
   const executionAsyncId = async_hooks.executionAsyncId;
-  const asyncLocalStore: {[index: string]: any} = {};
+  const asyncLocalStore: { [index: string]: any } = {};
 
-  store = new class {
-    getStore(): AsyncState | undefined { return asyncLocalStore[executionAsyncId()] as unknown as AsyncState; }
-    enterWith(store: AsyncState): void { asyncLocalStore[executionAsyncId()] = store; }
-  }();
+  store = {
+    getStore(): AsyncState | undefined {
+      return asyncLocalStore[executionAsyncId()] as unknown as AsyncState;
+    },
+
+    enterWith(s: AsyncState): void {
+      asyncLocalStore[executionAsyncId()] = s;
+    },
+  };
 
   async_hooks.createHook({
-    init(asyncId: number, type: string, triggerId: number) { asyncLocalStore[asyncId] = asyncLocalStore[triggerId]; },
-    destroy(asyncId: number) { delete asyncLocalStore[asyncId]; }
+    init(asyncId: number, type: string, triggerId: number) {
+      asyncLocalStore[asyncId] = asyncLocalStore[triggerId];
+    },
+    destroy(asyncId: number) {
+      delete asyncLocalStore[asyncId];
+    },
   }).enable();
 }
 
@@ -49,23 +61,28 @@ class ContextManager {
     let asyncState = store.getStore();
 
     if (asyncState === undefined) {
-      asyncState = {context: new SpanContext(), spans: []};
+      asyncState = { context: new SpanContext(), spans: [] };
       store.enterWith(asyncState);
     }
 
     return asyncState;
   }
 
-  get current(): Context { return this.asyncState.context; }
-  get spans(): Span[] { return this.asyncState.spans; }
+  get current(): Context {
+    return this.asyncState.context;
+  }
+
+  get spans(): Span[] {
+    return this.asyncState.spans;
+  }
 
   spansDup(): Span[] {
     let asyncState = store.getStore();
 
     if (asyncState === undefined) {
-      asyncState = {context: new SpanContext(), spans: []};
+      asyncState = { context: new SpanContext(), spans: [] };
     } else {
-      asyncState = {context: asyncState.context, spans: [...asyncState.spans]};
+      asyncState = { context: asyncState.context, spans: [...asyncState.spans] };
     }
 
     store.enterWith(asyncState);
@@ -78,13 +95,12 @@ class ContextManager {
   }
 
   restore(context: Context, spans: Span[]): void {
-    store.enterWith({context, spans: spans || []});
+    store.enterWith({ context, spans: spans || [] });
   }
 
   withSpan(span: Span, callback: (...args: any[]) => any, ...args: any[]): any {
-    if(!span.startTime)
+    if (!span.startTime)
       span.start();
-
     try {
       return callback(...args);
     } catch (e) {
@@ -96,9 +112,8 @@ class ContextManager {
   }
 
   async withSpanAwait(span: Span, callback: (...args: any[]) => any, ...args: any[]): Promise<any> {
-    if(!span.startTime)
+    if (!span.startTime)
       span.start();
-
     try {
       return await callback(...args);
     } catch (e) {
diff --git a/src/trace/context/SpanContext.ts b/src/trace/context/SpanContext.ts
index c08f524..6eb2c59 100644
--- a/src/trace/context/SpanContext.ts
+++ b/src/trace/context/SpanContext.ts
@@ -26,12 +26,12 @@ import Segment from '../../trace/context/Segment';
 import EntrySpan from '../../trace/span/EntrySpan';
 import ExitSpan from '../../trace/span/ExitSpan';
 import LocalSpan from '../../trace/span/LocalSpan';
-import buffer from '../../agent/Buffer';
 import { createLogger } from '../../logging';
 import { executionAsyncId } from 'async_hooks';
 import { ContextCarrier } from './ContextCarrier';
 import ContextManager from './ContextManager';
 import { SpanType } from '../../proto/language-agent/Tracing_pb';
+import { emitter } from '../../lib/EventEmitter';
 
 const logger = createLogger(__filename);
 
@@ -155,7 +155,11 @@ export default class SpanContext implements Context {
   }
 
   start(span: Span): Context {
-    logger.debug('Starting span', { span: span.operation, spans: ContextManager.spans, nSpans: this.nSpans });
+    logger.debug('Starting span', {
+      span: span.operation,
+      spans: ContextManager.spans,
+      nSpans: this.nSpans,
+    });
 
     this.nSpans += 1;
     if (ContextManager.spans.every((s) => s.id !== span.id)) {
@@ -166,7 +170,11 @@ export default class SpanContext implements Context {
   }
 
   stop(span: Span): boolean {
-    logger.debug('Stopping span', { span: span.operation, spans: ContextManager.spans, nSpans: this.nSpans });
+    logger.debug('Stopping span', {
+      span: span.operation,
+      spans: ContextManager.spans,
+      nSpans: this.nSpans,
+    });
 
     span.finish(this.segment);
 
@@ -176,7 +184,7 @@ export default class SpanContext implements Context {
     }
 
     if (--this.nSpans === 0) {
-      buffer.put(this.segment);
+      emitter.emit('segment-finished', this.segment);
       ContextManager.clear();
       return true;
     }
@@ -185,7 +193,11 @@ export default class SpanContext implements Context {
   }
 
   async(span: Span) {
-    logger.debug('Async span', { span: span.operation, spans: ContextManager.spans, nSpans: this.nSpans });
+    logger.debug('Async span', {
+      span: span.operation,
+      spans: ContextManager.spans,
+      nSpans: this.nSpans,
+    });
 
     const idx = ContextManager.spans.indexOf(span);
 
@@ -199,7 +211,11 @@ export default class SpanContext implements Context {
   }
 
   resync(span: Span) {
-    logger.debug('Resync span', { span: span.operation, spans: ContextManager.spans, nSpans: this.nSpans });
+    logger.debug('Resync span', {
+      span: span.operation,
+      spans: ContextManager.spans,
+      nSpans: this.nSpans,
+    });
 
     if ((span.context as SpanContext).nSpans === 1) {
       ContextManager.restore(span.context, [span]);
diff --git a/src/trace/span/EntrySpan.ts b/src/trace/span/EntrySpan.ts
index 59e841b..6c49e9a 100644
--- a/src/trace/span/EntrySpan.ts
+++ b/src/trace/span/EntrySpan.ts
@@ -47,9 +47,7 @@ export default class EntrySpan extends StackedSpan {
 
     const ref = SegmentRef.fromCarrier(carrier);
 
-    if (!this.refs.includes(ref)) {
-      this.refs.push(ref);
-    }
+    this.refer(ref);
 
     return this;
   }
diff --git a/src/trace/span/StackedSpan.ts b/src/trace/span/StackedSpan.ts
index 8c1886f..3b1fc74 100644
--- a/src/trace/span/StackedSpan.ts
+++ b/src/trace/span/StackedSpan.ts
@@ -18,12 +18,8 @@
  */
 
 import Span, { SpanCtorOptions } from '../../trace/span/Span';
-import Segment from '../../trace/context/Segment';
-import { createLogger } from '../../logging';
 import { SpanType } from '../../proto/language-agent/Tracing_pb';
 
-const logger = createLogger(__filename);
-
 export default class StackedSpan extends Span {
   depth = 0;
 
diff --git a/tests/plugins/http/client.ts b/tests/plugins/axios/client.ts
similarity index 79%
copy from tests/plugins/http/client.ts
copy to tests/plugins/axios/client.ts
index 2c2ce5e..91f435d 100644
--- a/tests/plugins/http/client.ts
+++ b/tests/plugins/axios/client.ts
@@ -18,21 +18,19 @@
  */
 
 import * as http from 'http';
-import Agent from '../../../src';
+import agent from '../../../src';
+import axios from 'axios';
 
-Agent.start({
+agent.start({
   serviceName: 'client',
   maxBufferSize: 1000,
 });
 
 const server = http.createServer((req, res) => {
-  http
-    .request(`http://${process.env.SERVER || 'localhost:5000'}${req.url}`, (r) => {
-      let data = '';
-      r.on('data', (chunk) => (data += chunk));
-      r.on('end', () => res.end(data));
-    })
-    .end();
+  axios
+  .get(`http://${process.env.SERVER || 'localhost:5000'}${req.url}`)
+  .then((r) => res.end(JSON.stringify(r.data)))
+  .catch(err => res.end(JSON.stringify(err)));
 });
 
 server.listen(5001, () => console.info('Listening on port 5001...'));
diff --git a/tests/plugins/http/docker-compose.yml b/tests/plugins/axios/docker-compose.yml
similarity index 92%
copy from tests/plugins/http/docker-compose.yml
copy to tests/plugins/axios/docker-compose.yml
index 8905cdb..b88cbee 100644
--- a/tests/plugins/http/docker-compose.yml
+++ b/tests/plugins/axios/docker-compose.yml
@@ -15,7 +15,7 @@
 # limitations under the License.
 #
 
-version: '2.1'
+version: '3.8'
 
 services:
   collector:
@@ -29,17 +29,16 @@ services:
     extends:
       file: ../common/base-compose.yml
       service: agent
-    container_name: server
     ports:
       - 5000:5000
     volumes:
-      - .:/app/tests/plugins/http
+      - .:/app/tests/plugins/express
     healthcheck:
       test: [ "CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/5000" ]
       interval: 5s
       timeout: 60s
       retries: 120
-    entrypoint: [ 'bash', '-c', 'npx ts-node /app/tests/plugins/http/server.ts' ]
+    entrypoint: [ 'bash', '-c', 'npx ts-node /app/tests/plugins/axios/server.ts' ]
     depends_on:
       collector:
         condition: service_healthy
@@ -48,7 +47,6 @@ services:
     extends:
       file: ../common/base-compose.yml
       service: agent
-    container_name: client
     ports:
       - 5001:5001
     environment:
@@ -58,7 +56,7 @@ services:
       interval: 5s
       timeout: 60s
       retries: 120
-    entrypoint: [ 'bash', '-c', 'npx ts-node /app/tests/plugins/http/client.ts' ]
+    entrypoint: [ 'bash', '-c', 'npx ts-node /app/tests/plugins/axios/client.ts' ]
     depends_on:
       server:
         condition: service_healthy
diff --git a/tests/plugins/http/expected.data.yaml b/tests/plugins/axios/expected.data.yaml
similarity index 62%
copy from tests/plugins/http/expected.data.yaml
copy to tests/plugins/axios/expected.data.yaml
index 29e6cff..1f24544 100644
--- a/tests/plugins/http/expected.data.yaml
+++ b/tests/plugins/axios/expected.data.yaml
@@ -21,74 +21,89 @@ segmentItems:
     segments:
       - segmentId: not null
         spans:
-          - operationName: /test
-            operationId: 0
-            parentSpanId: -1
-            spanId: 0
-            spanLayer: Http
-            startTime: gt 0
-            endTime: gt 0
-            componentId: 49
-            isError: false
-            spanType: Entry
-            peer: server:5000
-            skipAnalysis: false
-            tags:
-              - { key: http.url, value: server:5000/test }
-              - { key: http.status.code, value: '200' }
-            refs:
-              - { parentEndpoint: '', networkAddress: 'server:5000', refType: CrossProcess,
-                  parentSpanId: 1, parentTraceSegmentId: not null, parentServiceInstance: not null,
-                  parentService: client, traceId: not null }
           - operationName: /json
             operationId: 0
             parentSpanId: 0
             spanId: 1
             spanLayer: Http
+            tags:
+              - key: http.url
+                value: httpbin.org:80/json
+              - key: http.status.code
+                value: '200'
+              - key: http.status.msg
+                value: OK
             startTime: gt 0
             endTime: gt 0
-            componentId: 2
-            isError: false
+            componentId: 4005
             spanType: Exit
             peer: httpbin.org
             skipAnalysis: false
-            tags:
-              - { key: http.url, value: httpbin.org/json }
-              - { key: http.status.code, value: '200' }
-              - { key: http.status.msg, value: OK }
-  - serviceName: client
-    segmentSize: 1
-    segments:
-      - segmentId: not null
-        spans:
-          - operationName: /test
+          - operationName: /axios
             operationId: 0
             parentSpanId: -1
             spanId: 0
             spanLayer: Http
+            tags:
+              - key: http.url
+                value: server:5000/axios
+              - key: http.status.code
+                value: '200'
+              - key: http.status.msg
+                value: OK
+            refs:
+              - parentEndpoint: ''
+                networkAddress: server:5000
+                refType: CrossProcess
+                parentSpanId: 1
+                parentTraceSegmentId: not null
+                parentServiceInstance: not null
+                parentService: client
+                traceId: not null
             startTime: gt 0
             endTime: gt 0
             componentId: 49
-            isError: false
             spanType: Entry
-            peer: localhost:5001
+            peer: server:5000
             skipAnalysis: false
-            tags:
-              - { key: http.url, value: localhost:5001/test }
-              - { key: http.status.code, value: '200' }
-          - operationName: /test
+  - serviceName: client
+    segmentSize: 1
+    segments:
+      - segmentId: not null
+        spans:
+          - operationName: /axios
             operationId: 0
             parentSpanId: 0
             spanId: 1
             spanLayer: Http
+            tags:
+              - key: http.url
+                value: server:5000/axios
+              - key: http.status.code
+                value: '200'
+              - key: http.status.msg
+                value: OK
             startTime: gt 0
             endTime: gt 0
-            componentId: 2
-            isError: false
+            componentId: 4005
             spanType: Exit
             peer: server:5000
             skipAnalysis: false
+          - operationName: /axios
+            operationId: 0
+            parentSpanId: -1
+            spanId: 0
+            spanLayer: Http
             tags:
-              - { key: http.url, value: 'server:5000/test' }
-              - { key: http.status.code, value: '200' }
-              - { key: http.status.msg, value: OK }
+              - key: http.url
+                value: localhost:5001/axios
+              - key: http.status.code
+                value: '200'
+              - key: http.status.msg
+                value: OK
+            startTime: gt 0
+            endTime: gt 0
+            componentId: 49
+            spanType: Entry
+            peer: localhost:5001
+            skipAnalysis: false
diff --git a/tests/plugins/http/server.ts b/tests/plugins/axios/server.ts
similarity index 77%
copy from tests/plugins/http/server.ts
copy to tests/plugins/axios/server.ts
index b9cbc2f..bbca28d 100644
--- a/tests/plugins/http/server.ts
+++ b/tests/plugins/axios/server.ts
@@ -17,22 +17,18 @@
  *
  */
 
-import Agent from '../../../src';
+import agent from '../../../src';
 import * as http from 'http';
+import axios from 'axios';
 
-Agent.start({
+agent.start({
   serviceName: 'server',
   maxBufferSize: 1000,
 });
 
-const server = http.createServer((req, res) => {
-  http
-    .request('http://httpbin.org/json', (r) => {
-      let data = '';
-      r.on('data', (chunk) => (data += chunk));
-      r.on('end', () => res.end(data));
-    })
-    .end();
+const server = http.createServer(async (req, res) => {
+  const r = await axios.get('http://httpbin.org/json');
+  res.end(JSON.stringify(r.data));
 });
 
 server.listen(5000, () => console.info('Listening on port 5000...'));
diff --git a/tests/plugins/http/test.ts b/tests/plugins/axios/test.ts
similarity index 94%
copy from tests/plugins/http/test.ts
copy to tests/plugins/axios/test.ts
index 07966da..63156be 100644
--- a/tests/plugins/http/test.ts
+++ b/tests/plugins/axios/test.ts
@@ -30,8 +30,8 @@ describe('plugin tests', () => {
 
   beforeAll(async () => {
     compose = await new DockerComposeEnvironment(rootDir, 'docker-compose.yml')
-      .withWaitStrategy('client', Wait.forHealthCheck())
-      .up();
+    .withWaitStrategy('client', Wait.forHealthCheck())
+    .up();
   });
 
   afterAll(async () => {
@@ -39,7 +39,7 @@ describe('plugin tests', () => {
   });
 
   it(__filename, async () => {
-    await waitForExpect(async () => expect((await axios.get('http://localhost:5001/test')).status).toBe(200));
+    await waitForExpect(async () => expect((await axios.get('http://localhost:5001/axios')).status).toBe(200));
 
     const expectedData = await fs.readFile(path.join(rootDir, 'expected.data.yaml'), 'utf8');
 
diff --git a/tests/plugins/common/Dockerfile.agent b/tests/plugins/common/Dockerfile.agent
index 4c51529..5e907d4 100644
--- a/tests/plugins/common/Dockerfile.agent
+++ b/tests/plugins/common/Dockerfile.agent
@@ -24,4 +24,3 @@ WORKDIR /app
 ADD $ROOT /app
 
 RUN npm install request && npm install
-
diff --git a/tests/plugins/common/base-compose.yml b/tests/plugins/common/base-compose.yml
index 1e16c0a..677493b 100644
--- a/tests/plugins/common/base-compose.yml
+++ b/tests/plugins/common/base-compose.yml
@@ -22,7 +22,6 @@ services:
     build:
       context: ../../../
       dockerfile: tests/plugins/common/Dockerfile.tool
-    container_name: collector
     ports:
       - 12800:12800
     networks:
diff --git a/tests/plugins/http/client.ts b/tests/plugins/express/client.ts
similarity index 69%
copy from tests/plugins/http/client.ts
copy to tests/plugins/express/client.ts
index 2c2ce5e..20e0487 100644
--- a/tests/plugins/http/client.ts
+++ b/tests/plugins/express/client.ts
@@ -18,21 +18,24 @@
  */
 
 import * as http from 'http';
-import Agent from '../../../src';
+import agent from '../../../src';
+import express from 'express';
 
-Agent.start({
+agent.start({
   serviceName: 'client',
   maxBufferSize: 1000,
 });
 
-const server = http.createServer((req, res) => {
+const app = express();
+
+app.get('/express', (req, res) => {
   http
-    .request(`http://${process.env.SERVER || 'localhost:5000'}${req.url}`, (r) => {
-      let data = '';
-      r.on('data', (chunk) => (data += chunk));
-      r.on('end', () => res.end(data));
-    })
-    .end();
+  .request(`http://${process.env.SERVER || 'localhost:5000'}${req.url}`, (r) => {
+    let data = '';
+    r.on('data', (chunk) => (data += chunk));
+    r.on('end', () => res.send(data));
+  })
+  .end();
 });
 
-server.listen(5001, () => console.info('Listening on port 5001...'));
+app.listen(5001, () => console.info('Listening on port 5001...'));
diff --git a/tests/plugins/http/docker-compose.yml b/tests/plugins/express/docker-compose.yml
similarity index 92%
copy from tests/plugins/http/docker-compose.yml
copy to tests/plugins/express/docker-compose.yml
index 8905cdb..224e4c6 100644
--- a/tests/plugins/http/docker-compose.yml
+++ b/tests/plugins/express/docker-compose.yml
@@ -15,7 +15,7 @@
 # limitations under the License.
 #
 
-version: '2.1'
+version: '3.8'
 
 services:
   collector:
@@ -29,17 +29,16 @@ services:
     extends:
       file: ../common/base-compose.yml
       service: agent
-    container_name: server
     ports:
       - 5000:5000
     volumes:
-      - .:/app/tests/plugins/http
+      - .:/app/tests/plugins/express
     healthcheck:
       test: [ "CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/5000" ]
       interval: 5s
       timeout: 60s
       retries: 120
-    entrypoint: [ 'bash', '-c', 'npx ts-node /app/tests/plugins/http/server.ts' ]
+    entrypoint: [ 'bash', '-c', 'npx ts-node /app/tests/plugins/express/server.ts' ]
     depends_on:
       collector:
         condition: service_healthy
@@ -48,7 +47,6 @@ services:
     extends:
       file: ../common/base-compose.yml
       service: agent
-    container_name: client
     ports:
       - 5001:5001
     environment:
@@ -58,7 +56,7 @@ services:
       interval: 5s
       timeout: 60s
       retries: 120
-    entrypoint: [ 'bash', '-c', 'npx ts-node /app/tests/plugins/http/client.ts' ]
+    entrypoint: [ 'bash', '-c', 'npx ts-node /app/tests/plugins/express/client.ts' ]
     depends_on:
       server:
         condition: service_healthy
diff --git a/tests/plugins/http/expected.data.yaml b/tests/plugins/express/expected.data.yaml
similarity index 62%
copy from tests/plugins/http/expected.data.yaml
copy to tests/plugins/express/expected.data.yaml
index 29e6cff..4f6311a 100644
--- a/tests/plugins/http/expected.data.yaml
+++ b/tests/plugins/express/expected.data.yaml
@@ -21,74 +21,89 @@ segmentItems:
     segments:
       - segmentId: not null
         spans:
-          - operationName: /test
-            operationId: 0
-            parentSpanId: -1
-            spanId: 0
-            spanLayer: Http
-            startTime: gt 0
-            endTime: gt 0
-            componentId: 49
-            isError: false
-            spanType: Entry
-            peer: server:5000
-            skipAnalysis: false
-            tags:
-              - { key: http.url, value: server:5000/test }
-              - { key: http.status.code, value: '200' }
-            refs:
-              - { parentEndpoint: '', networkAddress: 'server:5000', refType: CrossProcess,
-                  parentSpanId: 1, parentTraceSegmentId: not null, parentServiceInstance: not null,
-                  parentService: client, traceId: not null }
           - operationName: /json
             operationId: 0
             parentSpanId: 0
             spanId: 1
             spanLayer: Http
+            tags:
+              - key: http.url
+                value: httpbin.org/json
+              - key: http.status.code
+                value: '200'
+              - key: http.status.msg
+                value: OK
             startTime: gt 0
             endTime: gt 0
             componentId: 2
-            isError: false
             spanType: Exit
             peer: httpbin.org
             skipAnalysis: false
-            tags:
-              - { key: http.url, value: httpbin.org/json }
-              - { key: http.status.code, value: '200' }
-              - { key: http.status.msg, value: OK }
-  - serviceName: client
-    segmentSize: 1
-    segments:
-      - segmentId: not null
-        spans:
-          - operationName: /test
+          - operationName: /express
             operationId: 0
             parentSpanId: -1
             spanId: 0
             spanLayer: Http
+            tags:
+              - key: http.url
+                value: server:5000/express
+              - key: http.status.code
+                value: '200'
+              - key: http.status.msg
+                value: OK
+            refs:
+              - parentEndpoint: ''
+                networkAddress: server:5000
+                refType: CrossProcess
+                parentSpanId: 1
+                parentTraceSegmentId: not null
+                parentServiceInstance: not null
+                parentService: client
+                traceId: not null
             startTime: gt 0
             endTime: gt 0
-            componentId: 49
-            isError: false
+            componentId: 4002
             spanType: Entry
-            peer: localhost:5001
+            peer: server:5000
             skipAnalysis: false
-            tags:
-              - { key: http.url, value: localhost:5001/test }
-              - { key: http.status.code, value: '200' }
-          - operationName: /test
+  - serviceName: client
+    segmentSize: 1
+    segments:
+      - segmentId: not null
+        spans:
+          - operationName: /express
             operationId: 0
             parentSpanId: 0
             spanId: 1
             spanLayer: Http
+            tags:
+              - key: http.url
+                value: server:5000/express
+              - key: http.status.code
+                value: '200'
+              - key: http.status.msg
+                value: OK
             startTime: gt 0
             endTime: gt 0
             componentId: 2
-            isError: false
             spanType: Exit
             peer: server:5000
             skipAnalysis: false
+          - operationName: /express
+            operationId: 0
+            parentSpanId: -1
+            spanId: 0
+            spanLayer: Http
             tags:
-              - { key: http.url, value: 'server:5000/test' }
-              - { key: http.status.code, value: '200' }
-              - { key: http.status.msg, value: OK }
+              - key: http.url
+                value: localhost:5001/express
+              - key: http.status.code
+                value: '200'
+              - key: http.status.msg
+                value: OK
+            startTime: gt 0
+            endTime: gt 0
+            componentId: 4002
+            spanType: Entry
+            peer: localhost:5001
+            skipAnalysis: false
diff --git a/tests/plugins/http/server.ts b/tests/plugins/express/server.ts
similarity index 70%
copy from tests/plugins/http/server.ts
copy to tests/plugins/express/server.ts
index b9cbc2f..9ce3346 100644
--- a/tests/plugins/http/server.ts
+++ b/tests/plugins/express/server.ts
@@ -17,22 +17,25 @@
  *
  */
 
-import Agent from '../../../src';
+import agent from '../../../src';
 import * as http from 'http';
 
-Agent.start({
+import express from 'express';
+
+agent.start({
   serviceName: 'server',
   maxBufferSize: 1000,
 });
+const app = express();
 
-const server = http.createServer((req, res) => {
+app.get('/express', (req, res) => {
   http
-    .request('http://httpbin.org/json', (r) => {
-      let data = '';
-      r.on('data', (chunk) => (data += chunk));
-      r.on('end', () => res.end(data));
-    })
-    .end();
+  .request('http://httpbin.org/json', (r) => {
+    let data = '';
+    r.on('data', (chunk) => (data += chunk));
+    r.on('end', () => res.send(data));
+  })
+  .end();
 });
 
-server.listen(5000, () => console.info('Listening on port 5000...'));
+app.listen(5000, () => console.info('Listening on port 5000...'));
diff --git a/tests/plugins/http/test.ts b/tests/plugins/express/test.ts
similarity index 94%
copy from tests/plugins/http/test.ts
copy to tests/plugins/express/test.ts
index 07966da..b046f34 100644
--- a/tests/plugins/http/test.ts
+++ b/tests/plugins/express/test.ts
@@ -30,8 +30,8 @@ describe('plugin tests', () => {
 
   beforeAll(async () => {
     compose = await new DockerComposeEnvironment(rootDir, 'docker-compose.yml')
-      .withWaitStrategy('client', Wait.forHealthCheck())
-      .up();
+    .withWaitStrategy('client', Wait.forHealthCheck())
+    .up();
   });
 
   afterAll(async () => {
@@ -39,7 +39,7 @@ describe('plugin tests', () => {
   });
 
   it(__filename, async () => {
-    await waitForExpect(async () => expect((await axios.get('http://localhost:5001/test')).status).toBe(200));
+    await waitForExpect(async () => expect((await axios.get('http://localhost:5001/express')).status).toBe(200));
 
     const expectedData = await fs.readFile(path.join(rootDir, 'expected.data.yaml'), 'utf8');
 
diff --git a/tests/plugins/http/client.ts b/tests/plugins/http/client.ts
index 2c2ce5e..c1ee8a9 100644
--- a/tests/plugins/http/client.ts
+++ b/tests/plugins/http/client.ts
@@ -18,21 +18,21 @@
  */
 
 import * as http from 'http';
-import Agent from '../../../src';
+import agent from '../../../src';
 
-Agent.start({
+agent.start({
   serviceName: 'client',
   maxBufferSize: 1000,
 });
 
 const server = http.createServer((req, res) => {
   http
-    .request(`http://${process.env.SERVER || 'localhost:5000'}${req.url}`, (r) => {
-      let data = '';
-      r.on('data', (chunk) => (data += chunk));
-      r.on('end', () => res.end(data));
-    })
-    .end();
+  .request(`http://${process.env.SERVER || 'localhost:5000'}${req.url}`, (r) => {
+    let data = '';
+    r.on('data', (chunk) => (data += chunk));
+    r.on('end', () => res.end(data));
+  })
+  .end();
 });
 
 server.listen(5001, () => console.info('Listening on port 5001...'));
diff --git a/tests/plugins/http/docker-compose.yml b/tests/plugins/http/docker-compose.yml
index 8905cdb..e5d8ca7 100644
--- a/tests/plugins/http/docker-compose.yml
+++ b/tests/plugins/http/docker-compose.yml
@@ -29,7 +29,6 @@ services:
     extends:
       file: ../common/base-compose.yml
       service: agent
-    container_name: server
     ports:
       - 5000:5000
     volumes:
@@ -48,7 +47,6 @@ services:
     extends:
       file: ../common/base-compose.yml
       service: agent
-    container_name: client
     ports:
       - 5001:5001
     environment:
diff --git a/tests/plugins/http/expected.data.yaml b/tests/plugins/http/expected.data.yaml
index 29e6cff..1e9e6f2 100644
--- a/tests/plugins/http/expected.data.yaml
+++ b/tests/plugins/http/expected.data.yaml
@@ -21,25 +21,6 @@ segmentItems:
     segments:
       - segmentId: not null
         spans:
-          - operationName: /test
-            operationId: 0
-            parentSpanId: -1
-            spanId: 0
-            spanLayer: Http
-            startTime: gt 0
-            endTime: gt 0
-            componentId: 49
-            isError: false
-            spanType: Entry
-            peer: server:5000
-            skipAnalysis: false
-            tags:
-              - { key: http.url, value: server:5000/test }
-              - { key: http.status.code, value: '200' }
-            refs:
-              - { parentEndpoint: '', networkAddress: 'server:5000', refType: CrossProcess,
-                  parentSpanId: 1, parentTraceSegmentId: not null, parentServiceInstance: not null,
-                  parentService: client, traceId: not null }
           - operationName: /json
             operationId: 0
             parentSpanId: 0
@@ -48,19 +29,16 @@ segmentItems:
             startTime: gt 0
             endTime: gt 0
             componentId: 2
-            isError: false
             spanType: Exit
             peer: httpbin.org
             skipAnalysis: false
             tags:
-              - { key: http.url, value: httpbin.org/json }
-              - { key: http.status.code, value: '200' }
-              - { key: http.status.msg, value: OK }
-  - serviceName: client
-    segmentSize: 1
-    segments:
-      - segmentId: not null
-        spans:
+              - key: http.url
+                value: httpbin.org/json
+              - key: http.status.code
+                value: '200'
+              - key: http.status.msg
+                value: OK
           - operationName: /test
             operationId: 0
             parentSpanId: -1
@@ -69,13 +47,30 @@ segmentItems:
             startTime: gt 0
             endTime: gt 0
             componentId: 49
-            isError: false
             spanType: Entry
-            peer: localhost:5001
+            peer: server:5000
             skipAnalysis: false
             tags:
-              - { key: http.url, value: localhost:5001/test }
-              - { key: http.status.code, value: '200' }
+              - key: http.url
+                value: server:5000/test
+              - key: http.status.code
+                value: '200'
+              - key: http.status.msg
+                value: OK
+            refs:
+              - parentEndpoint: ''
+                networkAddress: server:5000
+                refType: CrossProcess
+                parentSpanId: 1
+                parentTraceSegmentId: not null
+                parentServiceInstance: not null
+                parentService: client
+                traceId: not null
+  - serviceName: client
+    segmentSize: 1
+    segments:
+      - segmentId: not null
+        spans:
           - operationName: /test
             operationId: 0
             parentSpanId: 0
@@ -84,11 +79,31 @@ segmentItems:
             startTime: gt 0
             endTime: gt 0
             componentId: 2
-            isError: false
             spanType: Exit
             peer: server:5000
             skipAnalysis: false
             tags:
-              - { key: http.url, value: 'server:5000/test' }
-              - { key: http.status.code, value: '200' }
-              - { key: http.status.msg, value: OK }
+              - key: http.url
+                value: server:5000/test
+              - key: http.status.code
+                value: '200'
+              - key: http.status.msg
+                value: OK
+          - operationName: /test
+            operationId: 0
+            parentSpanId: -1
+            spanId: 0
+            spanLayer: Http
+            startTime: gt 0
+            endTime: gt 0
+            componentId: 49
+            spanType: Entry
+            peer: localhost:5001
+            skipAnalysis: false
+            tags:
+              - key: http.url
+                value: localhost:5001/test
+              - key: http.status.code
+                value: '200'
+              - key: http.status.msg
+                value: OK
diff --git a/tests/plugins/http/server.ts b/tests/plugins/http/server.ts
index b9cbc2f..bf362c7 100644
--- a/tests/plugins/http/server.ts
+++ b/tests/plugins/http/server.ts
@@ -17,22 +17,22 @@
  *
  */
 
-import Agent from '../../../src';
+import agent from '../../../src';
 import * as http from 'http';
 
-Agent.start({
+agent.start({
   serviceName: 'server',
   maxBufferSize: 1000,
 });
 
 const server = http.createServer((req, res) => {
   http
-    .request('http://httpbin.org/json', (r) => {
-      let data = '';
-      r.on('data', (chunk) => (data += chunk));
-      r.on('end', () => res.end(data));
-    })
-    .end();
+  .request('http://httpbin.org/json', (r) => {
+    let data = '';
+    r.on('data', (chunk) => (data += chunk));
+    r.on('end', () => res.end(data));
+  })
+  .end();
 });
 
 server.listen(5000, () => console.info('Listening on port 5000...'));
diff --git a/tests/plugins/http/test.ts b/tests/plugins/http/test.ts
index 07966da..3550b0e 100644
--- a/tests/plugins/http/test.ts
+++ b/tests/plugins/http/test.ts
@@ -30,8 +30,8 @@ describe('plugin tests', () => {
 
   beforeAll(async () => {
     compose = await new DockerComposeEnvironment(rootDir, 'docker-compose.yml')
-      .withWaitStrategy('client', Wait.forHealthCheck())
-      .up();
+    .withWaitStrategy('client', Wait.forHealthCheck())
+    .up();
   });
 
   afterAll(async () => {