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:03 UTC

[skywalking-nodejs] 01/01: Finalize 0.1.0

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 () => {