You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2020/08/31 07:46:55 UTC
[skywalking] branch master updated: Support Browser protocol at OAP
(#4228)
This is an automated email from the ASF dual-hosted git repository.
wusheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking.git
The following commit(s) were added to refs/heads/master by this push:
new 7ef8b3e Support Browser protocol at OAP (#4228)
7ef8b3e is described below
commit 7ef8b3e476001154ba5d600f7206add0277d4d24
Author: zhang-wei <pk...@outlook.com>
AuthorDate: Mon Aug 31 15:46:37 2020 +0800
Support Browser protocol at OAP (#4228)
---
.github/workflows/e2e.js.yaml | 55 ++++
README.md | 2 +-
docs/README.md | 2 +
docs/en/concepts-and-designs/oal.md | 6 +
docs/en/concepts-and-designs/scope-definitions.md | 102 ++++++--
docs/en/guides/storage-extention.md | 1 +
docs/en/protocols/Browser-Protocol.md | 18 ++
docs/en/protocols/README.md | 6 +
docs/en/setup/backend/backend-receivers.md | 5 +
.../analyzer/provider/jvm/JVMSourceDispatcher.java | 5 +-
.../apache/skywalking/oal/rt/grammar/OALLexer.g4 | 10 +
.../apache/skywalking/oal/rt/grammar/OALParser.g4 | 6 +-
.../skywalking/oal/rt/parser/AnalysisResult.java | 6 +
.../skywalking/oal/rt/parser/DeepAnalysis.java | 19 +-
.../skywalking/oal/rt/parser/ScriptParserTest.java | 23 ++
oap-server/server-bootstrap/pom.xml | 7 +-
.../src/main/resources/application.yml | 4 +
.../src/main/resources/oal/browser.oal | 63 +++++
.../skywalking/oap/server/core/CoreModule.java | 2 +
.../oap/server/core/CoreModuleProvider.java | 2 +
.../server/core/analysis/DispatcherManager.java | 4 +-
.../oap/server/core/analysis/NodeType.java | 2 +
.../server/core/analysis/metrics/RateMetrics.java | 72 +++++
.../core/analysis/metrics/expression/InMatch.java | 1 -
.../manual/BrowserAppTrafficSourceDispatcher.java} | 31 +--
.../endpoint/BrowserAppPageTrafficDispatcher.java | 35 +++
.../manual/errorlog/BrowserErrorLogRecord.java | 132 ++++++++++
.../errorlog/BrowserErrorLogRecordDispatcher.java | 39 +++
.../BrowserAppSingleVersionTrafficDispatcher.java | 36 +++
.../service/BrowserAppTrafficDispatcher.java | 35 +++
.../core/browser/source/BrowserAppPagePerf.java | 54 ++++
.../core/browser/source/BrowserAppPageTraffic.java | 54 ++++
.../server/core/browser/source/BrowserAppPerf.java | 39 +++
.../core/browser/source/BrowserAppPerfSource.java | 47 ++++
.../source/BrowserAppSingleVersionPerf.java | 54 ++++
.../source/BrowserAppSingleVersionTraffic.java | 54 ++++
.../core/browser/source/BrowserAppTraffic.java | 39 +++
.../browser/source/BrowserAppTrafficCategory.java | 25 +-
.../browser/source/BrowserAppTrafficSource.java | 45 ++++
.../core/browser/source/BrowserErrorCategory.java | 49 ++++
.../core/browser/source/BrowserErrorLog.java | 66 +++++
.../server/core/query/BrowserLogQueryService.java | 65 +++++
.../query/input/BrowserErrorLogQueryCondition.java | 25 +-
.../server/core/query/type/BrowserErrorLog.java | 28 +-
.../server/core/query/type/BrowserErrorLogs.java} | 23 +-
.../oap/server/core/query/type/ErrorCategory.java | 20 +-
.../oap/server/core/source/DefaultScopeDefine.java | 9 +
.../oap/server/core/storage/StorageModule.java | 4 +-
.../core/storage/query/IBrowserLogQueryDAO.java | 68 +++++
.../skywalking/oap/server/core/CoreModuleTest.java | 2 +-
.../oap/query/graphql/GraphQLQueryProvider.java | 75 +++---
.../query/graphql/resolver/BrowserLogQuery.java | 59 +++++
.../src/main/resources/query-protocol | 2 +-
oap-server/server-receiver-plugin/pom.xml | 1 +
.../skywalking-browser-receiver-plugin/pom.xml | 38 +++
.../receiver/browser/module/BrowserModule.java} | 22 +-
.../browser/provider/BrowserModuleProvider.java | 107 ++++++++
.../browser/provider/BrowserOALDefine.java} | 23 +-
.../provider/BrowserServiceModuleConfig.java | 21 +-
.../handler/BrowserPerfServiceHandler.java | 144 ++++++++++
.../parser/errorlog/BrowserErrorLogDecorator.java | 99 +++++++
.../provider/parser/errorlog/ErrorLogAnalyzer.java | 67 +++++
.../errorlog/ErrorLogParserListenerManager.java} | 21 +-
.../listener/ErrorLogAnalysisListener.java} | 34 ++-
.../errorlog/listener/ErrorLogListenerFactory.java | 15 +-
.../errorlog/listener/ErrorLogRecordListener.java | 118 +++++++++
.../errorlog/listener/ErrorLogRecordSampler.java} | 34 ++-
.../MultiScopesErrorLogAnalysisListener.java | 83 ++++++
.../parser/errorlog/listener/SourceBuilder.java | 112 ++++++++
.../performance/BrowserPerfDataDecorator.java | 114 ++++++++
.../parser/performance/PerfDataAnalyzer.java | 67 +++++
.../PerfDataParserListenerManager.java} | 21 +-
.../MultiScopesPerfDataAnalysisListener.java | 109 ++++++++
.../listener/PerfDataAnalysisListener.java} | 34 ++-
.../listener/PerfDataListenerFactory.java | 19 +-
.../parser/performance/listener/SourceBuilder.java | 201 ++++++++++++++
...ywalking.oap.server.library.module.ModuleDefine | 19 ++
...alking.oap.server.library.module.ModuleProvider | 19 ++
.../StorageModuleElasticsearchProvider.java | 3 +
.../elasticsearch/query/BrowserLogQueryEsDAO.java | 99 +++++++
.../StorageModuleElasticsearch7Provider.java | 68 ++---
.../query/BrowserLogQueryEs7DAO.java | 98 +++++++
.../plugin/influxdb/InfluxStorageProvider.java | 11 +-
.../plugin/influxdb/query/BrowserLogQuery.java | 124 +++++++++
.../plugin/influxdb/query/MetadataQuery.java | 2 +-
.../storage/plugin/jdbc/h2/H2StorageProvider.java | 3 +
.../plugin/jdbc/h2/dao/H2BrowserLogQueryDAO.java | 125 +++++++++
.../plugin/jdbc/mysql/MySQLStorageProvider.java | 2 +
.../jdbc/mysql/MysqlBrowserLogQueryDAO.java} | 33 ++-
.../tool/profile/core/MockCoreModuleProvider.java | 2 +
.../apache/skywalking/e2e/SimpleQueryClient.java | 45 +++-
.../skywalking/e2e/browser/BrowserErrorLog.java} | 28 +-
.../e2e/browser/BrowserErrorLogMatcher.java | 94 +++++++
.../e2e/browser/BrowserErrorLogQuery.java | 33 ++-
.../skywalking/e2e/browser/BrowserErrorLogs.java} | 16 +-
.../e2e/browser/BrowserErrorLogsData.java} | 15 +-
.../e2e/browser/BrowserErrorLogsMatcher.java | 38 ++-
.../e2e/metrics/BrowserMetricsQuery.java | 112 ++++++++
.../skywalking/e2e/metrics/MetricsMatcher.java | 13 +-
.../org/apache/skywalking/e2e/utils/Times.java | 3 +-
.../src/main/resources/browser-error-logs.gql | 39 +++
.../src/main/resources/browser-services.gql | 31 +++
test/e2e/e2e-protocol/src/main/proto | 2 +-
test/e2e/e2e-test/docker/browser/Dockerfile.h2 | 24 ++
.../e2e-test/docker/browser/docker-compose.es6.yml | 44 ++++
.../e2e-test/docker/browser/docker-compose.es7.yml | 44 ++++
.../e2e-test/docker/browser/docker-compose.h2.yml | 45 ++++
.../docker/browser/docker-compose.influxdb.yml | 42 +++
.../docker/browser/docker-compose.mysql.yml | 47 ++++
test/e2e/e2e-test/docker/browser/download-mysql.sh | 26 ++
.../java/org/apache/skywalking/e2e/ClusterE2E.java | 4 +-
.../skywalking/e2e/base/SkyWalkingTestAdapter.java | 4 +-
.../apache/skywalking/e2e/browser/BrowserE2E.java | 290 +++++++++++++++++++++
.../test/resources/expected/browser/error-log.yml | 28 ++
.../test/resources/expected/browser/page-path.yml | 18 ++
.../test/resources/expected/browser/services.yml | 18 ++
.../test/resources/expected/browser/version.yml | 18 ++
test/e2e/pom.xml | 4 +
118 files changed, 4488 insertions(+), 386 deletions(-)
diff --git a/.github/workflows/e2e.js.yaml b/.github/workflows/e2e.js.yaml
new file mode 100644
index 0000000..d0a87ef
--- /dev/null
+++ b/.github/workflows/e2e.js.yaml
@@ -0,0 +1,55 @@
+# 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. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# 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.
+
+name: E2E
+
+on:
+ pull_request:
+ push:
+ branches:
+ - master
+ tags:
+ - 'v*'
+env:
+ SKIP_TEST: true
+
+jobs:
+ JavaScriptClient:
+ name: Java Script Client
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ storage: ['h2', 'mysql', 'es6', 'es7', 'influxdb']
+ env:
+ SW_STORAGE: ${{ matrix.storage }}
+ steps:
+ - uses: actions/checkout@v2
+ - name: checkout submodules
+ shell: bash
+ run: |
+ git submodule sync --recursive
+ git -c protocol.version=2 submodule update --init --force --recursive --depth=1
+ - name: Compile and Build
+ run: make docker && ES_VERSION=es7 TAG=latest-es7 make docker
+ - name: Copy dist package
+ run: cp -R dist test/e2e/
+ - name: Browser Receiver ${{ matrix.storage }}
+ run: ./mvnw --batch-mode -f test/e2e/pom.xml -am -DfailIfNoTests=false verify -Dit.test=org.apache.skywalking.e2e.browser.BrowserE2E
+ - uses: actions/upload-artifact@v1
+ if: failure()
+ with:
+ name: logs
+ path: logs
\ No newline at end of file
diff --git a/README.md b/README.md
index be2bc0b..6f88b88 100644
--- a/README.md
+++ b/README.md
@@ -28,7 +28,7 @@ The core features are following.
- Distributed tracing and context propagation
- Database access metrics. Detect slow database access statements(including SQL statements).
- Alarm
-
+- Browser performance monitoring
<img src="http://skywalking.apache.org/assets/frame-v8.jpg?u=20200423"/>
diff --git a/docs/README.md b/docs/README.md
index 1e86a23..982a920 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -66,6 +66,8 @@ If you are already familiar with SkyWalking, you could use this catalog to find
* [Plugin development guide](en/setup/service-agent/java-agent/README.md#plugin-development-guide).
* [Agent plugin tests and performance tests](en/setup/service-agent/java-agent/README.md#test).
* [Other language agents](en/setup/README.md#language-agents-in-service) includes Nginx LUA, Python, .NetCore, PHP, NodeJS, Go.
+ * Browser performance monitoring
+ * Track the performance of the browser, such as latency of redirect, dns, ttfb. For more information, [click here](https://github.com/apache/skywalking-client-js).
* Service Mesh
* [SkyWalking on Istio](en/setup/istio/README.md). Introduces how to use Istio Mixer bypass Adapter to work with SkyWalking.
* Use [ALS (access log service)](https://www.envoyproxy.io/docs/envoy/latest/api-v2/service/accesslog/v2/als.proto) to observe service mesh, without Mixer. Follow [document](en/setup/envoy/als_setting.md) to open it.
diff --git a/docs/en/concepts-and-designs/oal.md b/docs/en/concepts-and-designs/oal.md
index 195b5f7..c297072 100644
--- a/docs/en/concepts-and-designs/oal.md
+++ b/docs/en/concepts-and-designs/oal.md
@@ -53,6 +53,12 @@ In this case, input are request of each ServiceInstanceJVMCPU scope, avg is base
> endpoint_percent = from(Endpoint.*).percent(status == true);
In this case, all input are requests of each endpoint, condition is `endpoint.status == true`.
+- `rate`. The rate expressed as a fraction of 100, for the condition matched input.
+> browser_app_error_rate = from(BrowserAppTraffic.*).rate(trafficCategory == BrowserAppTrafficCategory.FIRST_ERROR, trafficCategory == BrowserAppTrafficCategory.NORMAL);
+
+In this case, all input are requests of each browser app traffic, `numerator` condition is `trafficCategory == BrowserAppTrafficCategory.FIRST_ERROR` and `denominator` condition is `trafficCategory == BrowserAppTrafficCategory.NORMAL`.
+The parameter (1) is the `numerator` condition.
+The parameter (2) is the `denominator` condition.
- `sum`. The sum calls per scope entity.
> service_calls_sum = from(Service.*).sum();
diff --git a/docs/en/concepts-and-designs/scope-definitions.md b/docs/en/concepts-and-designs/scope-definitions.md
index 0a368aa..f69d1bf 100644
--- a/docs/en/concepts-and-designs/scope-definitions.md
+++ b/docs/en/concepts-and-designs/scope-definitions.md
@@ -19,8 +19,8 @@ Calculate the metrics data from each request of the service.
| Name | Remarks | Group Key | Type |
|---|---|---|---|
-| id | Represent the unique id of the service | yes | int |
| name | Represent the name of the service | | string |
+| nodeType | Represent which kind of node of Service or Network address represents to, Such as: Normal, Database, MQ, Cache. | | enum |
| serviceInstanceName | Represent the name of the service instance id referred | | string |
| endpointName | Represent the name of the endpoint, such a full path of HTTP URI | | string |
| latency | Represent how much time of each request. | | int |
@@ -34,9 +34,9 @@ Calculate the metrics data from each request of the service instance.
| Name | Remarks | Group Key | Type |
|---|---|---|---|
-| id | Represent the unique id of the service instance, usually a number. | yes | int |
-| name | Represent the name of the service instance. Such as `ip:port@Service Name`. **Notice**: current native agent uses `processId@Service name` as instance name, which is useless when you want to setup a filter in aggregation. | | string|
+| name | Represent the name of the service instance. Such as `ip:port@Service Name`. **Notice**: current native agent uses `uuid@ipv4` as instance name, which is useless when you want to setup a filter in aggregation. | | string|
| serviceName | Represent the name of the service. | | string |
+| nodeType | Represent which kind of node of Service or Network address represents to, Such as: Normal, Database, MQ, Cache. | | enum |
| endpointName | Represent the name of the endpoint, such a full path of HTTP URI. | | string|
| latency | Represent how much time of each request. | | int |
| status | Represent whether success or fail of the request. | | bool(true for success) |
@@ -51,8 +51,7 @@ Calculate the metrics data if the service instance is a JVM and collected by jav
| Name | Remarks | Group Key | Type |
|---|---|---|---|
-| id | Represent the unique id of the service instance, usually a number. | yes | int |
-| name | Represent the name of the service instance. Such as `ip:port@Service Name`. **Notice**: current native agent uses `processId@Service name` as instance name, which is useless when you want to setup a filter in aggregation. | | string|
+| name | Represent the name of the service instance. Such as `ip:port@Service Name`. **Notice**: current native agent uses `uuid@ipv4` as instance name, which is useless when you want to setup a filter in aggregation. | | string|
| serviceName | Represent the name of the service. | | string |
| usePercent | Represent how much percent of cpu time cost| | double|
@@ -60,8 +59,7 @@ Calculate the metrics data if the service instance is a JVM and collected by jav
| Name | Remarks | Group Key | Type |
|---|---|---|---|
-| id | Represent the unique id of the service instance, usually a number. | yes | int |
-| name | Represent the name of the service instance. Such as `ip:port@Service Name`. **Notice**: current native agent uses `processId@Service name` as instance name, which is useless when you want to setup a filter in aggregation. | | string|
+| name | Represent the name of the service instance. Such as `ip:port@Service Name`. **Notice**: current native agent uses `uuid@ipv4` as instance name, which is useless when you want to setup a filter in aggregation. | | string|
| serviceName | Represent the name of the service. | | string |
| heapStatus | Represent this value the memory metrics values are heap or not | | bool |
| init | See JVM document | | long |
@@ -73,8 +71,7 @@ Calculate the metrics data if the service instance is a JVM and collected by jav
| Name | Remarks | Group Key | Type |
|---|---|---|---|
-| id | Represent the unique id of the service instance, usually a number. | yes | int |
-| name | Represent the name of the service instance. Such as `ip:port@Service Name`. **Notice**: current native agent uses `processId@Service name` as instance name, which is useless when you want to setup a filter in aggregation. | | string|
+| name | Represent the name of the service instance. Such as `ip:port@Service Name`. **Notice**: current native agent uses `uuid@ipv4` as instance name, which is useless when you want to setup a filter in aggregation. | | string|
| serviceName | Represent the name of the service. | | string |
| poolType | Include CODE_CACHE_USAGE, NEWGEN_USAGE, OLDGEN_USAGE, SURVIVOR_USAGE, PERMGEN_USAGE, METASPACE_USAGE based on different version of JVM. | | enum |
| init | See JVM document | | long |
@@ -86,8 +83,7 @@ Calculate the metrics data if the service instance is a JVM and collected by jav
| Name | Remarks | Group Key | Type |
|---|---|---|---|
-| id | Represent the unique id of the service instance, usually a number. | yes | int |
-| name | Represent the name of the service instance. Such as `ip:port@Service Name`. **Notice**: current native agent uses `processId@Service name` as instance name, which is useless when you want to setup a filter in aggregation. | | string|
+| name | Represent the name of the service instance. Such as `ip:port@Service Name`. **Notice**: current native agent uses `uuid@ipv4` as instance name, which is useless when you want to setup a filter in aggregation. | | string|
| serviceName | Represent the name of the service. | | string |
| phrase | Include NEW and OLD | | Enum |
| time | GC time cost | | long |
@@ -97,8 +93,7 @@ Calculate the metrics data if the service instance is a JVM and collected by jav
| Name | Remarks | Group Key | Type |
|---|---|---|---|
-| id | Represent the unique id of the service instance, usually a number. | yes | int |
-| name | Represent the name of the service instance. Such as `ip:port@Service Name`. **Notice**: current native agent uses `processId@Service name` as instance name, which is useless when you want to setup a filter in aggregation. | | string|
+| name | Represent the name of the service instance. Such as `ip:port@Service Name`. **Notice**: current native agent uses `uuid@ipv4` as instance name, which is useless when you want to setup a filter in aggregation. | | string|
| serviceName | Represent the name of the service. | | string |
| liveCount | Represent Current number of live threads | | int |
| daemonCount | Represent Current number of daemon threads | | int |
@@ -110,9 +105,9 @@ Calculate the metrics data from each request of the endpoint in the service.
| Name | Remarks | Group Key | Type |
|---|---|---|---|
-| id | Represent the unique id of the endpoint, usually a number. | yes | int |
| name | Represent the name of the endpoint, such a full path of HTTP URI. | | string |
| serviceName | Represent the name of the service. | | string |
+| serviceNodeType | Represent which kind of node of Service or Network address represents to, Such as: Normal, Database, MQ, Cache. | | enum |
| serviceInstanceName | Represent the name of the service instance id referred. | | string |
| latency | Represent how much time of each request. | | int |
| status | Represent whether success or fail of the request.| | bool(true for success) |
@@ -125,11 +120,11 @@ Calculate the metrics data from each request between one service and the other s
| Name | Remarks | Group Key | Type |
|---|---|---|---|
-| sourceServiceId | Represent the id of the source service. | yes | int |
| sourceServiceName | Represent the name of the source service. | | string |
+| sourceServiceNodeType | Represent which kind of node of Service or Network address represents to, Such as: Normal, Database, MQ, Cache. | | enum |
| sourceServiceInstanceName | Represent the name of the source service instance. | | string |
-| destServiceId | Represent the id of the destination service. | yes | string |
| destServiceName | Represent the name of the destination service. | | string |
+| destServiceNodeType | Represent which kind of node of Service or Network address represents to. | | enum |
| destServiceInstanceName | Represent the name of the destination service instance.| | string|
| endpoint | Represent the endpoint used in this call. | | string
| componentId | Represent the id of component used in this call. | yes | string
@@ -146,11 +141,11 @@ Calculate the metrics data from each request between one service instance and th
| Name | Remarks | Group Key | Type |
|---|---|---|---|
-| sourceServiceInstanceId | Represent the id of the source service instance. | yes | int|
| sourceServiceName | Represent the name of the source service. | | string |
+| sourceServiceNodeType | Represent which kind of node of Service or Network address represents to, Such as: Normal, Database, MQ, Cache. | | enum |
| sourceServiceInstanceName | Represent the name of the source service instance. | | string |
| destServiceName | Represent the name of the destination service. | | |
-| destServiceInstanceId | Represent the id of the destination service instance. | yes | int|
+| destServiceNodeType | Represent which kind of node of Service or Network address represents to, Such as: Normal, Database, MQ, Cache. | | string |
| destServiceInstanceName | Represent the name of the destination service instance. | | string |
| endpoint | Represent the endpoint used in this call. | | string
| componentId | Represent the id of component used in this call. | yes | string
@@ -169,13 +164,76 @@ including auto instrument agents(like Java, .NET), OpenCensus SkyWalking exporte
| Name | Remarks | Group Key | Type |
|---|---|---|---|
-| endpointId | Represent the id of the endpoint as parent in the dependency. | yes | int |
-| endpoint | Represent the endpoint as parent in the dependency.| | string|
-| childEndpointId | Represent the id of the endpoint being used by the parent endpoint in row(1) | yes | int|
-| childEndpoint| Represent the endpoint being used by the parent endpoint in row(2) | | string |
+| endpoint | Represent the endpoint as parent in the dependency.| | string|
+| serviceName | Represent the name of the service. | | string |
+| serviceNodeType | Represent which kind of node of Service or Network address represents to, Such as: Normal, Database, MQ, Cache. | | enum |
+| childEndpoint| Represent the endpoint being used by the parent endpoint in row(1) | | string |
+| childServiceName | Represent the endpoint being used by the parent service in row(1) | | string |
+| childServiceNodeType | Represent which kind of node of Service or Network address represents to, Such as: Normal, Database, MQ, Cache. | | string |
+| childServiceInstanceName | Represent the endpoint being used by the parent service instance in row(1) | | string |
| rpcLatency | Represent the latency of the RPC from some codes in the endpoint to the childEndpoint. Exclude the latency caused by the endpoint(1) itself.
| componentId | Represent the id of component used in this call. | yes | string
| status | Represent whether success or fail of the request.| | bool(true for success) |
| responseCode | Represent the response code of HTTP response, if this request is the HTTP call. | | int |
| type | Represent the type of each request. Such as: Database, HTTP, RPC, gRPC. | | enum |
| detectPoint | Represent where is the relation detected. Values: client, server, proxy. | yes | enum|
+
+
+### SCOPE `BrowserAppTraffic`
+
+Calculate the metrics data form each request of the browser app (only browser).
+
+| Name | Remarks | Group Key | Type |
+|---|---|---|---|
+| name | Represent the browser app name of each request. | | string |
+| count | Represents the number of request, fixed at 1. | | int |
+| trafficCategory | Represents traffic category, Values: NORMAL, FIRST_ERROR, ERROR | | enum |
+| errorCategory | Represents error category, Values: AJAX, RESOURCE, VUE, PROMISE, UNKNOWN | | enum |
+
+### SCOPE `BrowserAppSingleVersionTraffic`
+
+Calculate the metrics data form each request of the browser single version in the browser app (only browser).
+
+| Name | Remarks | Group Key | Type |
+|---|---|---|---|
+| name | Represent the single version name of each request. | | string |
+| serviceName | Represent the name of the browser app. | | string |
+| count | Represents the number of request, fixed at 1. | | int |
+| trafficCategory | Represents traffic category, Values: NORMAL, FIRST_ERROR, ERROR | | enum |
+| errorCategory | Represents error category, Values: AJAX, RESOURCE, VUE, PROMISE, UNKNOWN | | enum |
+
+### SCOPE `BrowserAppPageTraffic`
+
+Calculate the metrics data form each request of the page in the browser app (only browser).
+
+| Name | Remarks | Group Key | Type |
+|---|---|---|---|
+| name | Represent the page name of each request. | | string |
+| serviceName | Represent the name of the browser app. | | string |
+| count | Represents the number of request, fixed at 1. | | int |
+| trafficCategory | Represents the traffic category, Values: NORMAL, FIRST_ERROR, ERROR | | enum |
+| errorCategory | Represents the error category, Values: AJAX, RESOURCE, VUE, PROMISE, UNKNOWN | | enum |
+
+
+### SCOPE `BrowserAppPagePerf`
+
+Calculate the metrics data form each request of the page in the browser app (only browser).
+
+| Name | Remarks | Group Key | Type |
+|---|---|---|---|
+| name | Represent the page name of each request. | | string |
+| serviceName | Represent the name of the browser app. | | string |
+| redirectTime | Represents the time of redirection. | | int(in ms) |
+| dnsTime | Represents the DNS query time. | | int(in ms) |
+| ttfbTime | Time to first Byte. | | int(in ms) |
+| tcpTime | TCP connection time. | | int(in ms) |
+| transTime | Content transfer time. | | int(in ms) |
+| domAnalysisTime | Dom parsing time. | | int(in ms) |
+| fptTime | First paint time or blank screen time. | | int(in ms) |
+| domReadyTime | Dom ready time. | | int(in ms) |
+| loadPageTime | Page full load time. | | int(in ms) |
+| resTime | Synchronous load resources in the page. | | int(in ms) |
+| sslTime | Only valid for HTTPS. | | int(in ms) |
+| ttlTime | Time to interact. | | int(in ms) |
+| firstPackTime | First pack time. | | int(in ms) |
+| fmpTime | First Meaningful Paint. | | int(in ms) |
\ No newline at end of file
diff --git a/docs/en/guides/storage-extention.md b/docs/en/guides/storage-extention.md
index 5436332..371b908 100644
--- a/docs/en/guides/storage-extention.md
+++ b/docs/en/guides/storage-extention.md
@@ -33,6 +33,7 @@ Here is the list of all DAO interfaces in storage
1. IRegisterDAO
1. ILogQueryDAO
1. ITopNRecordsQueryDAO
+1. IBrowserLogQueryDAO
## Register all service implementations
In `public void prepare()`, use `this#registerServiceImplementation` method to do register binding your implementation with the above interfaces.
diff --git a/docs/en/protocols/Browser-Protocol.md b/docs/en/protocols/Browser-Protocol.md
new file mode 100644
index 0000000..679ecaf
--- /dev/null
+++ b/docs/en/protocols/Browser-Protocol.md
@@ -0,0 +1,18 @@
+# Browser Protocol
+
+Browser protocol describes the data format between [skywalking-client-js](https://github.com/apache/skywalking-client-js) and backend.
+
+## Overview
+
+Browser protocol is defined and provided in [gRPC format](https://github.com/apache/skywalking-data-collect-protocol/blob/master/browser/BrowserPerf.proto).
+
+### Send performance data and error log
+
+You can send performance data and error logs via the following services:
+
+1. `BrowserPerfService#collectPerfData` for performance data format.
+1. `BrowserPerfService#collectErrorLogs` for error log format.
+
+For error log format, there are some notices
+
+1. `BrowserErrorLog#uniqueId` should be unique in the whole distributed environments.
diff --git a/docs/en/protocols/README.md b/docs/en/protocols/README.md
index f94aa56..1b8a655 100644
--- a/docs/en/protocols/README.md
+++ b/docs/en/protocols/README.md
@@ -29,6 +29,12 @@ SkyWalking javaagent begins to support this since 8.0.0.
[SkyWalking Trace Data Protocol v3](Trace-Data-Protocol-v3.md) defines the communication way and format between agent and backend.
+### Browser probe protocol
+
+The browser probe, such as [skywalking-client-js](https://github.com/apache/skywalking-client-js) could use this protocol to send to backend. This service provided by gRPC.
+
+[SkyWalking Browser Protocol](Browser-Protocol.md) define the communication way and format between `skywalking-client-js` and backend.
+
### Service Mesh probe protocol
The probe in sidecar or proxy could use this protocol to send data to backendEnd. This service provided by gRPC, requires
the following key info:
diff --git a/docs/en/setup/backend/backend-receivers.md b/docs/en/setup/backend/backend-receivers.md
index 8db39ac..88aa26d 100644
--- a/docs/en/setup/backend/backend-receivers.md
+++ b/docs/en/setup/backend/backend-receivers.md
@@ -16,6 +16,7 @@ We have following receivers, and `default` implementors are provided in our Apac
1. **receiver_jaeger**. See [details](#jaeger-receiver).
1. **receiver-oc**. See [details](#opencensus-receiver).
1. **receiver-meter**. See [details](backend-meter.md).
+1. **receiver-browser**. gRPC services to accept browser performance data and error log.
The sample settings of these receivers should be already in default `application.yml`, and also list here
```yaml
@@ -60,6 +61,10 @@ receiver_zipkin:
receiver-profile:
selector: ${SW_RECEIVER_PROFILE:default}
default:
+
+receiver-browser:
+ selector: ${SW_RECEIVER_BROWSER:default}
+ default:
```
## gRPC/HTTP server for receiver
diff --git a/oap-server/analyzer/agent-analyzer/src/main/java/org/apache/skywalking/oap/server/analyzer/provider/jvm/JVMSourceDispatcher.java b/oap-server/analyzer/agent-analyzer/src/main/java/org/apache/skywalking/oap/server/analyzer/provider/jvm/JVMSourceDispatcher.java
index dd05946..0db68dc 100644
--- a/oap-server/analyzer/agent-analyzer/src/main/java/org/apache/skywalking/oap/server/analyzer/provider/jvm/JVMSourceDispatcher.java
+++ b/oap-server/analyzer/agent-analyzer/src/main/java/org/apache/skywalking/oap/server/analyzer/provider/jvm/JVMSourceDispatcher.java
@@ -19,6 +19,7 @@
package org.apache.skywalking.oap.server.analyzer.provider.jvm;
import java.util.List;
+import lombok.extern.slf4j.Slf4j;
import org.apache.skywalking.apm.network.common.v3.CPU;
import org.apache.skywalking.apm.network.language.agent.v3.GC;
import org.apache.skywalking.apm.network.language.agent.v3.JVMMetric;
@@ -38,11 +39,9 @@ import org.apache.skywalking.oap.server.core.source.ServiceInstanceJVMMemoryPool
import org.apache.skywalking.oap.server.core.source.ServiceInstanceJVMThread;
import org.apache.skywalking.oap.server.core.source.SourceReceiver;
import org.apache.skywalking.oap.server.library.module.ModuleManager;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+@Slf4j
public class JVMSourceDispatcher {
- private static final Logger LOGGER = LoggerFactory.getLogger(JVMSourceDispatcher.class);
private final SourceReceiver sourceReceiver;
public JVMSourceDispatcher(ModuleManager moduleManager) {
diff --git a/oap-server/oal-grammar/src/main/antlr4/org/apache/skywalking/oal/rt/grammar/OALLexer.g4 b/oap-server/oal-grammar/src/main/antlr4/org/apache/skywalking/oal/rt/grammar/OALLexer.g4
index aa598c2..316b558 100644
--- a/oap-server/oal-grammar/src/main/antlr4/org/apache/skywalking/oal/rt/grammar/OALLexer.g4
+++ b/oap-server/oal-grammar/src/main/antlr4/org/apache/skywalking/oal/rt/grammar/OALLexer.g4
@@ -45,6 +45,14 @@ SRC_SERVICE_INSTANCE_CLR_GC: 'ServiceInstanceCLRGC';
SRC_SERVICE_INSTANCE_CLR_THREAD: 'ServiceInstanceCLRThread';
SRC_ENVOY_INSTANCE_METRIC: 'EnvoyInstanceMetric';
+// Browser keywords
+SRC_BROWSER_APP_PERF: 'BrowserAppPerf';
+SRC_BROWSER_APP_PAGE_PERF: 'BrowserAppPagePerf';
+SRC_BROWSER_APP_SINGLE_VERSION_PERF: 'BrowserAppSingleVersionPerf';
+SRC_BROWSER_APP_TRAFFIC: 'BrowserAppTraffic';
+SRC_BROWSER_APP_PAGE_TRAFFIC: 'BrowserAppPageTraffic';
+SRC_BROWSER_APP_SINGLE_VERSION_TRAFFIC: 'BrowserAppSingleVersionTraffic';
+
//hard code entities, only used when need to be deactived.
//Disable is targeting @Stream#name
SRC_SEGMENT: 'segment';
@@ -61,6 +69,8 @@ SRC_PROFILE_TASK: 'profile_task';
SRC_PROFILE_TASK_LOG: 'profile_task_log';
SRC_PROFILE_THREAD_SHANPSHOT: 'profile_task_segment_snapshot';
+SRC_BROWSER_ERROR_LOG: 'browser_error_log';
+
// Constructors symbols
DOT: '.';
diff --git a/oap-server/oal-grammar/src/main/antlr4/org/apache/skywalking/oal/rt/grammar/OALParser.g4 b/oap-server/oal-grammar/src/main/antlr4/org/apache/skywalking/oal/rt/grammar/OALParser.g4
index cc0fd50..0296571 100644
--- a/oap-server/oal-grammar/src/main/antlr4/org/apache/skywalking/oal/rt/grammar/OALParser.g4
+++ b/oap-server/oal-grammar/src/main/antlr4/org/apache/skywalking/oal/rt/grammar/OALParser.g4
@@ -54,7 +54,9 @@ source
SRC_SERVICE_RELATION | SRC_SERVICE_INSTANCE_RELATION | SRC_ENDPOINT_RELATION |
SRC_SERVICE_INSTANCE_JVM_CPU | SRC_SERVICE_INSTANCE_JVM_MEMORY | SRC_SERVICE_INSTANCE_JVM_MEMORY_POOL | SRC_SERVICE_INSTANCE_JVM_GC | SRC_SERVICE_INSTANCE_JVM_THREAD |// JVM source of service instance
SRC_SERVICE_INSTANCE_CLR_CPU | SRC_SERVICE_INSTANCE_CLR_GC | SRC_SERVICE_INSTANCE_CLR_THREAD |
- SRC_ENVOY_INSTANCE_METRIC
+ SRC_ENVOY_INSTANCE_METRIC |
+ SRC_BROWSER_APP_PERF | SRC_BROWSER_APP_PAGE_PERF | SRC_BROWSER_APP_SINGLE_VERSION_PERF |
+ SRC_BROWSER_APP_TRAFFIC | SRC_BROWSER_APP_PAGE_TRAFFIC | SRC_BROWSER_APP_SINGLE_VERSION_TRAFFIC
;
disableSource
@@ -72,7 +74,7 @@ variable
;
aggregateFunction
- : functionName LR_BRACKET (funcParamExpression | (literalExpression (COMMA literalExpression)?))? RR_BRACKET
+ : functionName LR_BRACKET ((funcParamExpression (COMMA funcParamExpression)?) | (literalExpression (COMMA literalExpression)?))? RR_BRACKET
;
functionName
diff --git a/oap-server/oal-rt/src/main/java/org/apache/skywalking/oal/rt/parser/AnalysisResult.java b/oap-server/oal-rt/src/main/java/org/apache/skywalking/oal/rt/parser/AnalysisResult.java
index ad4f4e8..06ef512 100644
--- a/oap-server/oal-rt/src/main/java/org/apache/skywalking/oal/rt/parser/AnalysisResult.java
+++ b/oap-server/oal-rt/src/main/java/org/apache/skywalking/oal/rt/parser/AnalysisResult.java
@@ -57,6 +57,8 @@ public class AnalysisResult {
private List<ConditionExpression> funcConditionExpressions;
+ private int funcConditionExpressionGetIdx = 0;
+
private List<Argument> funcArgs;
private int argGetIdx = 0;
@@ -82,6 +84,10 @@ public class AnalysisResult {
funcConditionExpressions.add(conditionExpression);
}
+ public ConditionExpression getNextFuncConditionExpression() {
+ return funcConditionExpressions.get(funcConditionExpressionGetIdx++);
+ }
+
public void addFilterExpressions(Expression filterExpression) {
if (filterExpressions == null) {
filterExpressions = new LinkedList<>();
diff --git a/oap-server/oal-rt/src/main/java/org/apache/skywalking/oal/rt/parser/DeepAnalysis.java b/oap-server/oal-rt/src/main/java/org/apache/skywalking/oal/rt/parser/DeepAnalysis.java
index d1d065a..e968c33 100644
--- a/oap-server/oal-rt/src/main/java/org/apache/skywalking/oal/rt/parser/DeepAnalysis.java
+++ b/oap-server/oal-rt/src/main/java/org/apache/skywalking/oal/rt/parser/DeepAnalysis.java
@@ -31,6 +31,8 @@ import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.Entranc
import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.SourceFrom;
import org.apache.skywalking.oap.server.core.storage.annotation.Column;
+import static java.util.Objects.isNull;
+
public class DeepAnalysis {
public AnalysisResult analysis(AnalysisResult result) {
// 1. Set sub package name by source.metrics
@@ -85,16 +87,20 @@ public class DeepAnalysis {
Class<?> parameterType = parameter.getType();
Annotation[] parameterAnnotations = parameter.getAnnotations();
if (parameterAnnotations == null || parameterAnnotations.length == 0) {
- throw new IllegalArgumentException("Entrance method:" + entranceMethod + " doesn't include the annotation.");
+ throw new IllegalArgumentException(
+ "Entrance method:" + entranceMethod + " doesn't include the annotation.");
}
Annotation annotation = parameterAnnotations[0];
if (annotation instanceof SourceFrom) {
- entryMethod.addArg(parameterType, "source." + ClassMethodUtil.toGetMethod(result.getSourceAttribute()) + "()");
+ entryMethod.addArg(
+ parameterType, "source." + ClassMethodUtil.toGetMethod(result.getSourceAttribute()) + "()");
} else if (annotation instanceof ConstOne) {
entryMethod.addArg(parameterType, "1");
} else if (annotation instanceof org.apache.skywalking.oap.server.core.analysis.metrics.annotation.Expression) {
- if (result.getFuncConditionExpressions().size() == 1) {
- final ConditionExpression expression = result.getFuncConditionExpressions().get(0);
+ if (isNull(result.getFuncConditionExpressions()) || result.getFuncConditionExpressions().isEmpty()) {
+ throw new IllegalArgumentException("Entrance method:" + entranceMethod + " argument can't find funcParamExpression.");
+ } else {
+ ConditionExpression expression = result.getNextFuncConditionExpression();
final FilterMatchers.MatcherInfo matcherInfo = FilterMatchers.INSTANCE.find(expression.getExpressionType());
final String getter = matcherInfo.isBooleanType()
@@ -107,13 +113,12 @@ public class DeepAnalysis {
argExpression.setLeft("source." + getter + "()");
entryMethod.addArg(argExpression);
- } else {
- throw new IllegalArgumentException("Entrance method:" + entranceMethod + " argument can't find funcParamExpression.");
}
} else if (annotation instanceof Arg) {
entryMethod.addArg(parameterType, result.getNextFuncArg());
} else {
- throw new IllegalArgumentException("Entrance method:" + entranceMethod + " doesn't the expected annotation.");
+ throw new IllegalArgumentException(
+ "Entrance method:" + entranceMethod + " doesn't the expected annotation.");
}
}
diff --git a/oap-server/oal-rt/src/test/java/org/apache/skywalking/oal/rt/parser/ScriptParserTest.java b/oap-server/oal-rt/src/test/java/org/apache/skywalking/oal/rt/parser/ScriptParserTest.java
index fd91dd2..c927038 100644
--- a/oap-server/oal-rt/src/test/java/org/apache/skywalking/oal/rt/parser/ScriptParserTest.java
+++ b/oap-server/oal-rt/src/test/java/org/apache/skywalking/oal/rt/parser/ScriptParserTest.java
@@ -168,6 +168,29 @@ public class ScriptParserTest {
}
@Test
+ public void testParse5() throws IOException {
+ ScriptParser parser = ScriptParser.createFromScriptText(
+ "service_response_s4_summary = from(Service.latency).rate(param1 == true,param2 == false);",
+ TEST_SOURCE_PACKAGE
+ );
+ List<AnalysisResult> results = parser.parse().getMetricsStmts();
+ Assert.assertEquals(1, results.size());
+ AnalysisResult result = results.get(0);
+ Assert.assertEquals("rate", result.getAggregationFunctionName());
+ Assert.assertEquals(2, result.getFuncConditionExpressions().size());
+
+ ConditionExpression expression1 = result.getFuncConditionExpressions().get(0);
+ Assert.assertEquals("param1", expression1.getAttribute());
+ Assert.assertEquals("booleanMatch", expression1.getExpressionType());
+ Assert.assertEquals("true", expression1.getValue());
+
+ ConditionExpression expression2 = result.getFuncConditionExpressions().get(1);
+ Assert.assertEquals("param2", expression2.getAttribute());
+ Assert.assertEquals("booleanMatch", expression2.getExpressionType());
+ Assert.assertEquals("false", expression2.getValue());
+ }
+
+ @Test
public void testParse6() throws IOException {
ScriptParser parser = ScriptParser.createFromScriptText(
"service_response_s4_summary = from(Service.latency).filter(latency like \"%a\").sum();",
diff --git a/oap-server/server-bootstrap/pom.xml b/oap-server/server-bootstrap/pom.xml
index 4e2b982..d3a369b 100644
--- a/oap-server/server-bootstrap/pom.xml
+++ b/oap-server/server-bootstrap/pom.xml
@@ -126,6 +126,11 @@
<artifactId>skywalking-meter-receiver-plugin</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.skywalking</groupId>
+ <artifactId>skywalking-browser-receiver-plugin</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<!-- receiver module -->
<!-- fetcher module -->
@@ -264,4 +269,4 @@
</plugin>
</plugins>
</build>
-</project>
+</project>
\ No newline at end of file
diff --git a/oap-server/server-bootstrap/src/main/resources/application.yml b/oap-server/server-bootstrap/src/main/resources/application.yml
index a74ee81..f35e3a2 100755
--- a/oap-server/server-bootstrap/src/main/resources/application.yml
+++ b/oap-server/server-bootstrap/src/main/resources/application.yml
@@ -276,6 +276,10 @@ receiver_jaeger:
gRPCHost: ${SW_RECEIVER_JAEGER_HOST:0.0.0.0}
gRPCPort: ${SW_RECEIVER_JAEGER_PORT:14250}
+receiver-browser:
+ selector: ${SW_RECEIVER_BROWSER:default}
+ default:
+
query:
selector: ${SW_QUERY:graphql}
graphql:
diff --git a/oap-server/server-bootstrap/src/main/resources/oal/browser.oal b/oap-server/server-bootstrap/src/main/resources/oal/browser.oal
new file mode 100644
index 0000000..a7a4458
--- /dev/null
+++ b/oap-server/server-bootstrap/src/main/resources/oal/browser.oal
@@ -0,0 +1,63 @@
+/*
+* 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.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* 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.
+*
+*/
+// browser app
+browser_app_pv = from(BrowserAppTraffic.count).filter(trafficCategory == BrowserAppTrafficCategory.NORMAL).sum();
+browser_app_error_rate = from(BrowserAppTraffic.*).rate(trafficCategory == BrowserAppTrafficCategory.FIRST_ERROR,trafficCategory == BrowserAppTrafficCategory.NORMAL);
+browser_app_error_sum = from(BrowserAppTraffic.count).filter(trafficCategory != BrowserAppTrafficCategory.NORMAL).sum();
+
+// browser app single version
+browser_app_single_version_pv = from(BrowserAppSingleVersionTraffic.count).filter(trafficCategory == BrowserAppTrafficCategory.NORMAL).sum();
+browser_app_single_version_error_rate = from(BrowserAppSingleVersionTraffic.trafficCategory).rate(trafficCategory == BrowserAppTrafficCategory.FIRST_ERROR,trafficCategory == BrowserAppTrafficCategory.NORMAL);
+browser_app_single_version_error_sum = from(BrowserAppSingleVersionTraffic.count).filter(trafficCategory != BrowserAppTrafficCategory.NORMAL).sum();
+
+// browser app page
+browser_app_page_pv = from(BrowserAppPageTraffic.count).filter(trafficCategory == BrowserAppTrafficCategory.NORMAL).sum();
+browser_app_page_error_rate = from(BrowserAppPageTraffic.*).rate(trafficCategory == BrowserAppTrafficCategory.FIRST_ERROR,trafficCategory == BrowserAppTrafficCategory.NORMAL);
+browser_app_page_error_sum = from(BrowserAppPageTraffic.count).filter(trafficCategory != BrowserAppTrafficCategory.NORMAL).sum();
+
+browser_app_page_ajax_error_sum = from(BrowserAppPageTraffic.count).filter(trafficCategory != BrowserAppTrafficCategory.NORMAL).filter(errorCategory == BrowserErrorCategory.AJAX).sum();
+browser_app_page_resource_error_sum = from(BrowserAppPageTraffic.count).filter(trafficCategory != BrowserAppTrafficCategory.NORMAL).filter(errorCategory == BrowserErrorCategory.RESOURCE).sum();
+browser_app_page_js_error_sum = from(BrowserAppPageTraffic.count).filter(trafficCategory != BrowserAppTrafficCategory.NORMAL).filter(errorCategory in [BrowserErrorCategory.JS,BrowserErrorCategory.VUE,BrowserErrorCategory.PROMISE]).sum();
+browser_app_page_unknown_error_sum = from(BrowserAppPageTraffic.count).filter(trafficCategory != BrowserAppTrafficCategory.NORMAL).filter(errorCategory == BrowserErrorCategory.UNKNOWN).sum();
+
+// browser performance metrics
+browser_app_page_redirect_avg = from(BrowserAppPagePerf.redirectTime).longAvg();
+browser_app_page_dns_avg = from(BrowserAppPagePerf.dnsTime).longAvg();
+browser_app_page_ttfb_avg = from(BrowserAppPagePerf.ttfbTime).longAvg();
+browser_app_page_tcp_avg = from(BrowserAppPagePerf.tcpTime).longAvg();
+browser_app_page_trans_avg = from(BrowserAppPagePerf.transTime).longAvg();
+browser_app_page_dom_analysis_avg = from(BrowserAppPagePerf.domAnalysisTime).longAvg();
+browser_app_page_fpt_avg = from(BrowserAppPagePerf.fptTime).longAvg();
+browser_app_page_dom_ready_avg = from(BrowserAppPagePerf.domReadyTime).longAvg();
+browser_app_page_load_page_avg = from(BrowserAppPagePerf.loadPageTime).longAvg();
+browser_app_page_res_avg = from(BrowserAppPagePerf.resTime).longAvg();
+browser_app_page_ssl_avg = from(BrowserAppPagePerf.sslTime).longAvg();
+browser_app_page_ttl_avg = from(BrowserAppPagePerf.ttlTime).longAvg();
+browser_app_page_first_pack_avg = from(BrowserAppPagePerf.firstPackTime).longAvg();
+browser_app_page_fmp_avg = from(BrowserAppPagePerf.fmpTime).longAvg();
+
+browser_app_page_fpt_percentile = from(BrowserAppPagePerf.fptTime).percentile(10);
+browser_app_page_ttl_percentile = from(BrowserAppPagePerf.ttlTime).percentile(10);
+browser_app_page_dom_ready_percentile = from(BrowserAppPagePerf.domReadyTime).percentile(10);
+browser_app_page_load_page_percentile = from(BrowserAppPagePerf.loadPageTime).percentile(10);
+browser_app_page_first_pack_percentile = from(BrowserAppPagePerf.firstPackTime).percentile(10);
+browser_app_page_fmp_percentile = from(BrowserAppPagePerf.fmpTime).percentile(10);
+
+// Disable unnecessary hard core stream, targeting @Stream#name
+/////////
+//disable(browser_error_log);
\ No newline at end of file
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModule.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModule.java
index e796aca..358bc28 100755
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModule.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModule.java
@@ -33,6 +33,7 @@ import org.apache.skywalking.oap.server.core.oal.rt.OALEngineLoaderService;
import org.apache.skywalking.oap.server.core.profile.ProfileTaskMutationService;
import org.apache.skywalking.oap.server.core.query.AggregationQueryService;
import org.apache.skywalking.oap.server.core.query.AlarmQueryService;
+import org.apache.skywalking.oap.server.core.query.BrowserLogQueryService;
import org.apache.skywalking.oap.server.core.query.LogQueryService;
import org.apache.skywalking.oap.server.core.query.MetadataQueryService;
import org.apache.skywalking.oap.server.core.query.MetricsMetadataQueryService;
@@ -114,6 +115,7 @@ public class CoreModule extends ModuleDefine {
classes.add(AggregationQueryService.class);
classes.add(AlarmQueryService.class);
classes.add(TopNRecordsQueryService.class);
+ classes.add(BrowserLogQueryService.class);
}
private void addServerInterface(List<Class> classes) {
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleProvider.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleProvider.java
index 80521ca..b5f9bec 100755
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleProvider.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleProvider.java
@@ -52,6 +52,7 @@ import org.apache.skywalking.oap.server.core.oal.rt.OALEngineLoaderService;
import org.apache.skywalking.oap.server.core.profile.ProfileTaskMutationService;
import org.apache.skywalking.oap.server.core.query.AggregationQueryService;
import org.apache.skywalking.oap.server.core.query.AlarmQueryService;
+import org.apache.skywalking.oap.server.core.query.BrowserLogQueryService;
import org.apache.skywalking.oap.server.core.query.LogQueryService;
import org.apache.skywalking.oap.server.core.query.MetadataQueryService;
import org.apache.skywalking.oap.server.core.query.MetricsMetadataQueryService;
@@ -242,6 +243,7 @@ public class CoreModuleProvider extends ModuleProvider {
this.registerServiceImplementation(MetricsMetadataQueryService.class, new MetricsMetadataQueryService());
this.registerServiceImplementation(MetricsQueryService.class, new MetricsQueryService(getManager()));
this.registerServiceImplementation(TraceQueryService.class, new TraceQueryService(getManager()));
+ this.registerServiceImplementation(BrowserLogQueryService.class, new BrowserLogQueryService(getManager()));
this.registerServiceImplementation(LogQueryService.class, new LogQueryService(getManager()));
this.registerServiceImplementation(MetadataQueryService.class, new MetadataQueryService(getManager()));
this.registerServiceImplementation(AggregationQueryService.class, new AggregationQueryService(getManager()));
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/DispatcherManager.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/DispatcherManager.java
index 059d3b0..9f3f7ee 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/DispatcherManager.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/DispatcherManager.java
@@ -21,6 +21,7 @@ package org.apache.skywalking.oap.server.core.analysis;
import com.google.common.collect.ImmutableSet;
import com.google.common.reflect.ClassPath;
import java.io.IOException;
+import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
@@ -80,7 +81,8 @@ public class DispatcherManager implements DispatcherDetectorListener {
@Override
public void addIfAsSourceDispatcher(Class aClass) throws IllegalAccessException, InstantiationException {
- if (!aClass.isInterface() && SourceDispatcher.class.isAssignableFrom(aClass)) {
+ if (!aClass.isInterface() && !Modifier.isAbstract(
+ aClass.getModifiers()) && SourceDispatcher.class.isAssignableFrom(aClass)) {
Type[] genericInterfaces = aClass.getGenericInterfaces();
for (Type genericInterface : genericInterfaces) {
ParameterizedType anInterface = (ParameterizedType) genericInterface;
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/NodeType.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/NodeType.java
index 5c40922..30fe61d 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/NodeType.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/NodeType.java
@@ -89,6 +89,8 @@ public enum NodeType {
return MQ;
case 5:
return Cache;
+ case 6:
+ return Browser;
case 10:
return User;
case 11:
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/RateMetrics.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/RateMetrics.java
new file mode 100644
index 0000000..d4cedb6
--- /dev/null
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/RateMetrics.java
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.core.analysis.metrics;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.Entrance;
+import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.Expression;
+import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.MetricsFunction;
+import org.apache.skywalking.oap.server.core.query.sql.Function;
+import org.apache.skywalking.oap.server.core.storage.annotation.Column;
+
+@MetricsFunction(functionName = "rate")
+public abstract class RateMetrics extends Metrics implements IntValueHolder {
+ protected static final String DENOMINATOR = "denominator";
+ protected static final String NUMERATOR = "numerator";
+ protected static final String PERCENTAGE = "percentage";
+
+ @Getter
+ @Setter
+ @Column(columnName = DENOMINATOR)
+ private long denominator;
+ @Getter
+ @Setter
+ @Column(columnName = PERCENTAGE, dataType = Column.ValueDataType.COMMON_VALUE, function = Function.Avg)
+ private int percentage;
+ @Getter
+ @Setter
+ @Column(columnName = NUMERATOR)
+ private long numerator;
+
+ @Entrance
+ public final void combine(@Expression boolean isNumerator, @Expression boolean isDenominator) {
+ if (isNumerator) {
+ numerator++;
+ }
+ if (isDenominator) {
+ denominator++;
+ }
+ }
+
+ @Override
+ public final void combine(Metrics metrics) {
+ denominator += ((RateMetrics) metrics).denominator;
+ numerator += ((RateMetrics) metrics).numerator;
+ }
+
+ @Override
+ public void calculate() {
+ percentage = (int) (numerator * 10000 / denominator);
+ }
+
+ @Override
+ public int getValue() {
+ return percentage;
+ }
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/expression/InMatch.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/expression/InMatch.java
index 2873f3d..897bd00 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/expression/InMatch.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/expression/InMatch.java
@@ -22,7 +22,6 @@ import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.FilterM
@FilterMatcher
public class InMatch {
-
public boolean match(Object left, Object[] rights) {
for (Object right : rights) {
if (right instanceof String) {
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/expression/InMatch.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/manual/BrowserAppTrafficSourceDispatcher.java
similarity index 52%
copy from oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/expression/InMatch.java
copy to oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/manual/BrowserAppTrafficSourceDispatcher.java
index 2873f3d..9c35218 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/expression/InMatch.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/manual/BrowserAppTrafficSourceDispatcher.java
@@ -15,26 +15,21 @@
* limitations under the License.
*/
-package org.apache.skywalking.oap.server.core.analysis.metrics.expression;
+package org.apache.skywalking.oap.server.core.browser.manual;
-import java.util.Objects;
-import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.FilterMatcher;
+import org.apache.skywalking.oap.server.core.analysis.SourceDispatcher;
+import org.apache.skywalking.oap.server.core.browser.source.BrowserAppTrafficCategory;
+import org.apache.skywalking.oap.server.core.browser.source.BrowserAppTrafficSource;
-@FilterMatcher
-public class InMatch {
-
- public boolean match(Object left, Object[] rights) {
- for (Object right : rights) {
- if (right instanceof String) {
- String r = (String) right;
- if (r.startsWith("\"") && r.endsWith("\"")) {
- right = r.substring(1, r.length() - 1);
- }
- }
- if (Objects.equals(left, right)) {
- return true;
- }
+public abstract class BrowserAppTrafficSourceDispatcher<SOURCE extends BrowserAppTrafficSource> implements SourceDispatcher<SOURCE> {
+ @Override
+ public void dispatch(final SOURCE source) {
+ // filter error traffic
+ if (!source.getTrafficCategory().equals(BrowserAppTrafficCategory.NORMAL)) {
+ return;
}
- return false;
+ dispatchInterval(source);
}
+
+ protected abstract void dispatchInterval(SOURCE source);
}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/manual/endpoint/BrowserAppPageTrafficDispatcher.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/manual/endpoint/BrowserAppPageTrafficDispatcher.java
new file mode 100644
index 0000000..8df13e6
--- /dev/null
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/manual/endpoint/BrowserAppPageTrafficDispatcher.java
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.core.browser.manual.endpoint;
+
+import org.apache.skywalking.oap.server.core.analysis.SourceDispatcher;
+import org.apache.skywalking.oap.server.core.analysis.manual.endpoint.EndpointTraffic;
+import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
+import org.apache.skywalking.oap.server.core.browser.manual.BrowserAppTrafficSourceDispatcher;
+import org.apache.skywalking.oap.server.core.browser.source.BrowserAppPageTraffic;
+
+public class BrowserAppPageTrafficDispatcher extends BrowserAppTrafficSourceDispatcher<BrowserAppPageTraffic> implements SourceDispatcher<BrowserAppPageTraffic> {
+ @Override
+ protected void dispatchInterval(final BrowserAppPageTraffic source) {
+ EndpointTraffic traffic = new EndpointTraffic();
+ traffic.setTimeBucket(source.getTimeBucket());
+ traffic.setName(source.getName());
+ traffic.setServiceId(source.getServiceId());
+ MetricsStreamProcessor.getInstance().in(traffic);
+ }
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/manual/errorlog/BrowserErrorLogRecord.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/manual/errorlog/BrowserErrorLogRecord.java
new file mode 100644
index 0000000..1515a56
--- /dev/null
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/manual/errorlog/BrowserErrorLogRecord.java
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.core.browser.manual.errorlog;
+
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.Map;
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.skywalking.apm.util.StringUtil;
+import org.apache.skywalking.oap.server.core.Const;
+import org.apache.skywalking.oap.server.core.analysis.Stream;
+import org.apache.skywalking.oap.server.core.analysis.record.Record;
+import org.apache.skywalking.oap.server.core.analysis.worker.RecordStreamProcessor;
+import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;
+import org.apache.skywalking.oap.server.core.storage.StorageBuilder;
+import org.apache.skywalking.oap.server.core.storage.annotation.Column;
+import org.apache.skywalking.oap.server.library.util.CollectionUtils;
+
+@Stream(name = BrowserErrorLogRecord.INDEX_NAME, scopeId = DefaultScopeDefine.BROWSER_ERROR_LOG, builder = BrowserErrorLogRecord.Builder.class, processor = RecordStreamProcessor.class)
+public class BrowserErrorLogRecord extends Record {
+ public static final String INDEX_NAME = "browser_error_log";
+ public static final String UNIQUE_ID = "unique_id";
+ public static final String SERVICE_ID = "service_id";
+ public static final String SERVICE_VERSION_ID = "service_version_id";
+ public static final String PAGE_PATH_ID = "pate_path_id";
+ public static final String PAGE_PATH = "page_path";
+ public static final String TIMESTAMP = "timestamp";
+ public static final String ERROR_CATEGORY = "error_category";
+ public static final String DATA_BINARY = "data_binary";
+
+ @Override
+ public String id() {
+ return uniqueId;
+ }
+
+ @Setter
+ @Getter
+ @Column(columnName = UNIQUE_ID)
+ private String uniqueId;
+
+ @Setter
+ @Getter
+ @Column(columnName = SERVICE_ID)
+ private String serviceId;
+
+ @Setter
+ @Getter
+ @Column(columnName = SERVICE_VERSION_ID)
+ private String serviceVersionId;
+
+ @Setter
+ @Getter
+ @Column(columnName = PAGE_PATH_ID)
+ private String pagePathId;
+
+ @Setter
+ @Getter
+ @Column(columnName = PAGE_PATH, matchQuery = true)
+ private String pagePath;
+
+ @Setter
+ @Getter
+ @Column(columnName = TIMESTAMP)
+ private long timestamp;
+
+ @Setter
+ @Getter
+ @Column(columnName = ERROR_CATEGORY)
+ private int errorCategory;
+
+ @Setter
+ @Getter
+ @Column(columnName = DATA_BINARY)
+ private byte[] dataBinary;
+
+ public static class Builder implements StorageBuilder<BrowserErrorLogRecord> {
+ @Override
+ public BrowserErrorLogRecord map2Data(final Map<String, Object> dbMap) {
+ BrowserErrorLogRecord record = new BrowserErrorLogRecord();
+ record.setUniqueId((String) dbMap.get(UNIQUE_ID));
+ record.setServiceId((String) dbMap.get(SERVICE_ID));
+ record.setServiceVersionId((String) dbMap.get(SERVICE_VERSION_ID));
+ record.setPagePathId((String) dbMap.get(PAGE_PATH_ID));
+ record.setPagePath((String) dbMap.get(PAGE_PATH));
+ record.setTimestamp(((Number) dbMap.get(TIMESTAMP)).longValue());
+ record.setTimeBucket(((Number) dbMap.get(TIME_BUCKET)).longValue());
+ record.setErrorCategory(((Number) dbMap.get(ERROR_CATEGORY)).intValue());
+ String dataBinary = (String) dbMap.get(DATA_BINARY);
+ if (StringUtil.isEmpty(dataBinary)) {
+ record.setDataBinary(new byte[] {});
+ } else {
+ record.setDataBinary(Base64.getDecoder().decode(dataBinary));
+ }
+ return record;
+ }
+
+ @Override
+ public Map<String, Object> data2Map(final BrowserErrorLogRecord storageData) {
+ Map<String, Object> map = new HashMap<>();
+ map.put(UNIQUE_ID, storageData.getUniqueId());
+ map.put(SERVICE_ID, storageData.getServiceId());
+ map.put(SERVICE_VERSION_ID, storageData.getServiceVersionId());
+ map.put(PAGE_PATH_ID, storageData.getPagePathId());
+ map.put(PAGE_PATH, storageData.getPagePath());
+ map.put(TIMESTAMP, storageData.getTimestamp());
+ map.put(TIME_BUCKET, storageData.getTimeBucket());
+ map.put(ERROR_CATEGORY, storageData.getErrorCategory());
+ if (CollectionUtils.isEmpty(storageData.getDataBinary())) {
+ map.put(DATA_BINARY, Const.EMPTY_STRING);
+ } else {
+ map.put(DATA_BINARY, new String(Base64.getEncoder().encode(storageData.getDataBinary())));
+ }
+ return map;
+ }
+ }
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/manual/errorlog/BrowserErrorLogRecordDispatcher.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/manual/errorlog/BrowserErrorLogRecordDispatcher.java
new file mode 100644
index 0000000..e2a2630
--- /dev/null
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/manual/errorlog/BrowserErrorLogRecordDispatcher.java
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.core.browser.manual.errorlog;
+
+import org.apache.skywalking.oap.server.core.analysis.SourceDispatcher;
+import org.apache.skywalking.oap.server.core.analysis.worker.RecordStreamProcessor;
+import org.apache.skywalking.oap.server.core.browser.source.BrowserErrorLog;
+
+public class BrowserErrorLogRecordDispatcher implements SourceDispatcher<BrowserErrorLog> {
+ @Override
+ public void dispatch(final BrowserErrorLog source) {
+ BrowserErrorLogRecord record = new BrowserErrorLogRecord();
+ record.setUniqueId(source.getUniqueId());
+ record.setServiceId(source.getServiceId());
+ record.setServiceVersionId(source.getServiceVersionId());
+ record.setPagePathId(source.getPagePathId());
+ record.setPagePath(source.getPagePath());
+ record.setTimestamp(source.getTimestamp());
+ record.setTimeBucket(source.getTimeBucket());
+ record.setErrorCategory(source.getErrorCategory().getValue());
+ record.setDataBinary(source.getDataBinary());
+ RecordStreamProcessor.getInstance().in(record);
+ }
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/manual/instance/BrowserAppSingleVersionTrafficDispatcher.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/manual/instance/BrowserAppSingleVersionTrafficDispatcher.java
new file mode 100644
index 0000000..7ea9b3d
--- /dev/null
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/manual/instance/BrowserAppSingleVersionTrafficDispatcher.java
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.core.browser.manual.instance;
+
+import org.apache.skywalking.oap.server.core.analysis.SourceDispatcher;
+import org.apache.skywalking.oap.server.core.analysis.manual.instance.InstanceTraffic;
+import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
+import org.apache.skywalking.oap.server.core.browser.manual.BrowserAppTrafficSourceDispatcher;
+import org.apache.skywalking.oap.server.core.browser.source.BrowserAppSingleVersionTraffic;
+
+public class BrowserAppSingleVersionTrafficDispatcher extends BrowserAppTrafficSourceDispatcher<BrowserAppSingleVersionTraffic> implements SourceDispatcher<BrowserAppSingleVersionTraffic> {
+ @Override
+ protected void dispatchInterval(final BrowserAppSingleVersionTraffic source) {
+ InstanceTraffic traffic = new InstanceTraffic();
+ traffic.setTimeBucket(source.getTimeBucket());
+ traffic.setName(source.getName());
+ traffic.setServiceId(source.getServiceId());
+ traffic.setLastPingTimestamp(source.getTimeBucket());
+ MetricsStreamProcessor.getInstance().in(traffic);
+ }
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/manual/service/BrowserAppTrafficDispatcher.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/manual/service/BrowserAppTrafficDispatcher.java
new file mode 100644
index 0000000..f710872
--- /dev/null
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/manual/service/BrowserAppTrafficDispatcher.java
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.core.browser.manual.service;
+
+import org.apache.skywalking.oap.server.core.analysis.SourceDispatcher;
+import org.apache.skywalking.oap.server.core.analysis.manual.service.ServiceTraffic;
+import org.apache.skywalking.oap.server.core.analysis.worker.MetricsStreamProcessor;
+import org.apache.skywalking.oap.server.core.browser.manual.BrowserAppTrafficSourceDispatcher;
+import org.apache.skywalking.oap.server.core.browser.source.BrowserAppTraffic;
+
+public class BrowserAppTrafficDispatcher extends BrowserAppTrafficSourceDispatcher<BrowserAppTraffic> implements SourceDispatcher<BrowserAppTraffic> {
+ @Override
+ protected void dispatchInterval(final BrowserAppTraffic source) {
+ ServiceTraffic traffic = new ServiceTraffic();
+ traffic.setTimeBucket(source.getTimeBucket());
+ traffic.setName(source.getName());
+ traffic.setNodeType(source.getNodeType());
+ MetricsStreamProcessor.getInstance().in(traffic);
+ }
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserAppPagePerf.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserAppPagePerf.java
new file mode 100644
index 0000000..3a1f95c
--- /dev/null
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserAppPagePerf.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.core.browser.source;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.skywalking.oap.server.core.analysis.IDManager;
+import org.apache.skywalking.oap.server.core.source.ScopeDeclaration;
+import org.apache.skywalking.oap.server.core.source.ScopeDefaultColumn;
+
+import static org.apache.skywalking.oap.server.core.source.DefaultScopeDefine.BROWSER_APP_PAGE_PERF;
+import static org.apache.skywalking.oap.server.core.source.DefaultScopeDefine.ENDPOINT_CATALOG_NAME;
+
+@ScopeDeclaration(id = BROWSER_APP_PAGE_PERF, name = "BrowserAppPagePerf", catalog = ENDPOINT_CATALOG_NAME)
+@ScopeDefaultColumn.VirtualColumnDefinition(fieldName = "entityId", columnName = "entity_id", isID = true, type = String.class)
+public class BrowserAppPagePerf extends BrowserAppPerfSource {
+ @Override
+ public int scope() {
+ return BROWSER_APP_PAGE_PERF;
+ }
+
+ @Override
+ public String getEntityId() {
+ return IDManager.EndpointID.buildId(serviceId, name);
+ }
+
+ @Getter
+ @ScopeDefaultColumn.DefinedByField(columnName = "service_id")
+ private String serviceId;
+ @Getter
+ @Setter
+ @ScopeDefaultColumn.DefinedByField(columnName = "service_name", requireDynamicActive = true)
+ private String serviceName;
+
+ @Override
+ public void prepare() {
+ serviceId = IDManager.ServiceID.buildId(serviceName, nodeType);
+ }
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserAppPageTraffic.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserAppPageTraffic.java
new file mode 100644
index 0000000..b040e2b
--- /dev/null
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserAppPageTraffic.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.core.browser.source;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.skywalking.oap.server.core.analysis.IDManager;
+import org.apache.skywalking.oap.server.core.source.ScopeDeclaration;
+import org.apache.skywalking.oap.server.core.source.ScopeDefaultColumn;
+
+import static org.apache.skywalking.oap.server.core.source.DefaultScopeDefine.BROWSER_APP_PAGE_TRAFFIC;
+import static org.apache.skywalking.oap.server.core.source.DefaultScopeDefine.ENDPOINT_CATALOG_NAME;
+
+@ScopeDeclaration(id = BROWSER_APP_PAGE_TRAFFIC, name = "BrowserAppPageTraffic", catalog = ENDPOINT_CATALOG_NAME)
+@ScopeDefaultColumn.VirtualColumnDefinition(fieldName = "entityId", columnName = "entity_id", isID = true, type = String.class)
+public class BrowserAppPageTraffic extends BrowserAppTrafficSource {
+ @Override
+ public int scope() {
+ return BROWSER_APP_PAGE_TRAFFIC;
+ }
+
+ @Override
+ public String getEntityId() {
+ return IDManager.EndpointID.buildId(serviceId, name);
+ }
+
+ @Getter
+ @ScopeDefaultColumn.DefinedByField(columnName = "service_id")
+ private String serviceId;
+ @Getter
+ @Setter
+ @ScopeDefaultColumn.DefinedByField(columnName = "service_name", requireDynamicActive = true)
+ private String serviceName;
+
+ @Override
+ public void prepare() {
+ serviceId = IDManager.ServiceID.buildId(serviceName, nodeType);
+ }
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserAppPerf.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserAppPerf.java
new file mode 100644
index 0000000..12730ad
--- /dev/null
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserAppPerf.java
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.core.browser.source;
+
+import org.apache.skywalking.oap.server.core.analysis.IDManager;
+import org.apache.skywalking.oap.server.core.source.ScopeDeclaration;
+import org.apache.skywalking.oap.server.core.source.ScopeDefaultColumn;
+
+import static org.apache.skywalking.oap.server.core.source.DefaultScopeDefine.BROWSER_APP_PERF;
+import static org.apache.skywalking.oap.server.core.source.DefaultScopeDefine.SERVICE_CATALOG_NAME;
+
+@ScopeDeclaration(id = BROWSER_APP_PERF, name = "BrowserAppPerf", catalog = SERVICE_CATALOG_NAME)
+@ScopeDefaultColumn.VirtualColumnDefinition(fieldName = "entityId", columnName = "entity_id", isID = true, type = String.class)
+public class BrowserAppPerf extends BrowserAppPerfSource {
+ @Override
+ public int scope() {
+ return BROWSER_APP_PERF;
+ }
+
+ @Override
+ public String getEntityId() {
+ return IDManager.ServiceID.buildId(name, nodeType);
+ }
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserAppPerfSource.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserAppPerfSource.java
new file mode 100644
index 0000000..c3bbe65
--- /dev/null
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserAppPerfSource.java
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.core.browser.source;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.skywalking.oap.server.core.analysis.NodeType;
+import org.apache.skywalking.oap.server.core.source.Source;
+
+/**
+ * Browser performance details
+ */
+@Setter
+@Getter
+public abstract class BrowserAppPerfSource extends Source {
+ protected String name;
+ protected final NodeType nodeType = NodeType.Browser;
+ private int redirectTime;
+ private int dnsTime;
+ private int ttfbTime;
+ private int tcpTime;
+ private int transTime;
+ private int domAnalysisTime;
+ private int fptTime;
+ private int domReadyTime;
+ private int loadPageTime;
+ private int resTime;
+ private int sslTime;
+ private int ttlTime;
+ private int firstPackTime;
+ private int fmpTime;
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserAppSingleVersionPerf.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserAppSingleVersionPerf.java
new file mode 100644
index 0000000..bc86999
--- /dev/null
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserAppSingleVersionPerf.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.core.browser.source;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.skywalking.oap.server.core.analysis.IDManager;
+import org.apache.skywalking.oap.server.core.source.ScopeDeclaration;
+import org.apache.skywalking.oap.server.core.source.ScopeDefaultColumn;
+
+import static org.apache.skywalking.oap.server.core.source.DefaultScopeDefine.BROWSER_APP_SINGLE_VERSION_PERF;
+import static org.apache.skywalking.oap.server.core.source.DefaultScopeDefine.SERVICE_INSTANCE_CATALOG_NAME;
+
+@ScopeDeclaration(id = BROWSER_APP_SINGLE_VERSION_PERF, name = "BrowserAppSingleVersionPerf", catalog = SERVICE_INSTANCE_CATALOG_NAME)
+@ScopeDefaultColumn.VirtualColumnDefinition(fieldName = "entityId", columnName = "entity_id", isID = true, type = String.class)
+public class BrowserAppSingleVersionPerf extends BrowserAppPerfSource {
+ @Override
+ public int scope() {
+ return BROWSER_APP_SINGLE_VERSION_PERF;
+ }
+
+ @Override
+ public String getEntityId() {
+ return IDManager.ServiceInstanceID.buildId(serviceId, name);
+ }
+
+ @Getter
+ @ScopeDefaultColumn.DefinedByField(columnName = "service_id")
+ private String serviceId;
+ @Getter
+ @Setter
+ @ScopeDefaultColumn.DefinedByField(columnName = "service_name", requireDynamicActive = true)
+ private String serviceName;
+
+ @Override
+ public void prepare() {
+ serviceId = IDManager.ServiceID.buildId(serviceName, nodeType);
+ }
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserAppSingleVersionTraffic.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserAppSingleVersionTraffic.java
new file mode 100644
index 0000000..9adce36
--- /dev/null
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserAppSingleVersionTraffic.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.core.browser.source;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.skywalking.oap.server.core.analysis.IDManager;
+import org.apache.skywalking.oap.server.core.source.ScopeDeclaration;
+import org.apache.skywalking.oap.server.core.source.ScopeDefaultColumn;
+
+import static org.apache.skywalking.oap.server.core.source.DefaultScopeDefine.BROWSER_APP_SINGLE_VERSION_TRAFFIC;
+import static org.apache.skywalking.oap.server.core.source.DefaultScopeDefine.SERVICE_INSTANCE_CATALOG_NAME;
+
+@ScopeDeclaration(id = BROWSER_APP_SINGLE_VERSION_TRAFFIC, name = "BrowserAppSingleVersionTraffic", catalog = SERVICE_INSTANCE_CATALOG_NAME)
+@ScopeDefaultColumn.VirtualColumnDefinition(fieldName = "entityId", columnName = "entity_id", isID = true, type = String.class)
+public class BrowserAppSingleVersionTraffic extends BrowserAppTrafficSource {
+ @Override
+ public int scope() {
+ return BROWSER_APP_SINGLE_VERSION_TRAFFIC;
+ }
+
+ @Override
+ public String getEntityId() {
+ return IDManager.ServiceInstanceID.buildId(serviceId, name);
+ }
+
+ @Getter
+ @ScopeDefaultColumn.DefinedByField(columnName = "service_id")
+ private String serviceId;
+ @Getter
+ @Setter
+ @ScopeDefaultColumn.DefinedByField(columnName = "service_name", requireDynamicActive = true)
+ private String serviceName;
+
+ @Override
+ public void prepare() {
+ serviceId = IDManager.ServiceID.buildId(serviceName, nodeType);
+ }
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserAppTraffic.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserAppTraffic.java
new file mode 100644
index 0000000..aa0cb84
--- /dev/null
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserAppTraffic.java
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.core.browser.source;
+
+import org.apache.skywalking.oap.server.core.analysis.IDManager;
+import org.apache.skywalking.oap.server.core.source.ScopeDeclaration;
+import org.apache.skywalking.oap.server.core.source.ScopeDefaultColumn;
+
+import static org.apache.skywalking.oap.server.core.source.DefaultScopeDefine.BROWSER_APP_TRAFFIC;
+import static org.apache.skywalking.oap.server.core.source.DefaultScopeDefine.SERVICE_CATALOG_NAME;
+
+@ScopeDeclaration(id = BROWSER_APP_TRAFFIC, name = "BrowserAppTraffic", catalog = SERVICE_CATALOG_NAME)
+@ScopeDefaultColumn.VirtualColumnDefinition(fieldName = "entityId", columnName = "entity_id", isID = true, type = String.class)
+public class BrowserAppTraffic extends BrowserAppTrafficSource {
+ @Override
+ public int scope() {
+ return BROWSER_APP_TRAFFIC;
+ }
+
+ @Override
+ public String getEntityId() {
+ return IDManager.ServiceID.buildId(name, nodeType);
+ }
+}
diff --git a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserAppTrafficCategory.java
similarity index 63%
copy from test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java
copy to oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserAppTrafficCategory.java
index 6c35a88..0918da6 100644
--- a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserAppTrafficCategory.java
@@ -6,23 +6,28 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* 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.
- *
*/
-package org.apache.skywalking.e2e.utils;
-
-import java.time.LocalDateTime;
-import java.time.ZoneOffset;
+package org.apache.skywalking.oap.server.core.browser.source;
-public final class Times {
- public static LocalDateTime now() {
- return LocalDateTime.now(ZoneOffset.UTC);
- }
+public enum BrowserAppTrafficCategory {
+ /**
+ * From the BrowserPerfData.
+ */
+ NORMAL,
+ /**
+ * From the BrowserErrorLog and BrowserErrorLog#firstReportedError = true.
+ */
+ FIRST_ERROR,
+ /**
+ * From the BrowserErrorLog and BrowserErrorLog#firstReportedError = false.
+ */
+ ERROR
}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserAppTrafficSource.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserAppTrafficSource.java
new file mode 100644
index 0000000..d01b6df
--- /dev/null
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserAppTrafficSource.java
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.core.browser.source;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.skywalking.oap.server.core.analysis.NodeType;
+import org.apache.skywalking.oap.server.core.source.ScopeDefaultColumn;
+import org.apache.skywalking.oap.server.core.source.Source;
+
+/**
+ * From js client reported access traffic
+ */
+@Setter
+@Getter
+public abstract class BrowserAppTrafficSource extends Source {
+ @ScopeDefaultColumn.DefinedByField(columnName = "name", requireDynamicActive = true)
+ protected String name;
+
+ protected final NodeType nodeType = NodeType.Browser;
+
+ private final int count = 1;
+
+ private BrowserAppTrafficCategory trafficCategory;
+
+ /**
+ * if {@link #trafficCategory} is {@link BrowserAppTrafficCategory#NORMAL}, errorCategory is null.
+ */
+ private BrowserErrorCategory errorCategory;
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserErrorCategory.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserErrorCategory.java
new file mode 100644
index 0000000..442d96b
--- /dev/null
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserErrorCategory.java
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.core.browser.source;
+
+import lombok.Getter;
+import org.apache.skywalking.apm.network.language.agent.v3.ErrorCategory;
+
+public enum BrowserErrorCategory {
+ AJAX(0), RESOURCE(1), VUE(2), PROMISE(3), JS(4), UNKNOWN(5);
+
+ public static BrowserErrorCategory fromErrorCategory(ErrorCategory category) {
+ switch (category) {
+ case ajax:
+ return BrowserErrorCategory.AJAX;
+ case resource:
+ return BrowserErrorCategory.RESOURCE;
+ case vue:
+ return BrowserErrorCategory.VUE;
+ case promise:
+ return BrowserErrorCategory.PROMISE;
+ case js:
+ return BrowserErrorCategory.JS;
+ default:
+ return BrowserErrorCategory.UNKNOWN;
+ }
+ }
+
+ @Getter
+ private final int value;
+
+ BrowserErrorCategory(int value) {
+ this.value = value;
+ }
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserErrorLog.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserErrorLog.java
new file mode 100644
index 0000000..b8a723f
--- /dev/null
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/browser/source/BrowserErrorLog.java
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.core.browser.source;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.skywalking.oap.server.core.source.ScopeDeclaration;
+import org.apache.skywalking.oap.server.core.source.Source;
+
+import static org.apache.skywalking.oap.server.core.source.DefaultScopeDefine.BROWSER_ERROR_LOG;
+
+/**
+ * Browser error log raw data
+ */
+@ScopeDeclaration(id = BROWSER_ERROR_LOG, name = "BrowserErrorLog")
+public class BrowserErrorLog extends Source {
+ @Override
+ public int scope() {
+ return BROWSER_ERROR_LOG;
+ }
+
+ @Override
+ public String getEntityId() {
+ return uniqueId;
+ }
+
+ @Getter
+ @Setter
+ private String uniqueId;
+ @Getter
+ @Setter
+ private String serviceId;
+ @Getter
+ @Setter
+ private String serviceVersionId;
+ @Getter
+ @Setter
+ private String pagePathId;
+ @Getter
+ @Setter
+ private String pagePath;
+ @Getter
+ @Setter
+ private long timestamp;
+ @Getter
+ @Setter
+ private BrowserErrorCategory errorCategory;
+ @Getter
+ @Setter
+ private byte[] dataBinary;
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/BrowserLogQueryService.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/BrowserLogQueryService.java
new file mode 100644
index 0000000..fcbe3bb
--- /dev/null
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/BrowserLogQueryService.java
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.core.query;
+
+import java.io.IOException;
+import java.util.Optional;
+import lombok.RequiredArgsConstructor;
+import org.apache.skywalking.oap.server.core.browser.source.BrowserErrorCategory;
+import org.apache.skywalking.oap.server.core.query.type.BrowserErrorLogs;
+import org.apache.skywalking.oap.server.core.query.type.ErrorCategory;
+import org.apache.skywalking.oap.server.core.query.type.Pagination;
+import org.apache.skywalking.oap.server.core.storage.StorageModule;
+import org.apache.skywalking.oap.server.core.storage.query.IBrowserLogQueryDAO;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
+import org.apache.skywalking.oap.server.library.module.Service;
+
+@RequiredArgsConstructor
+public class BrowserLogQueryService implements Service {
+ private final ModuleManager moduleManager;
+ private IBrowserLogQueryDAO browserLogQueryDAO;
+
+ private IBrowserLogQueryDAO getBrowserLogQueryDAO() {
+ return Optional.ofNullable(browserLogQueryDAO).orElseGet(() -> {
+ browserLogQueryDAO = moduleManager.find(StorageModule.NAME)
+ .provider()
+ .getService(IBrowserLogQueryDAO.class);
+ return browserLogQueryDAO;
+ });
+ }
+
+ public BrowserErrorLogs queryBrowserErrorLogs(final String serviceId,
+ final String serviceVersionId,
+ final String pagePathId,
+ final String pagePath,
+ final ErrorCategory category,
+ final long startSecondTB,
+ final long endSecondTB,
+ final Pagination paging) throws IOException {
+ PaginationUtils.Page page = PaginationUtils.INSTANCE.exchange(paging);
+ BrowserErrorCategory errorCategory = Optional.ofNullable(category)
+ .map(c -> BrowserErrorCategory.valueOf(c.name()))
+ .orElse(null);
+
+ return getBrowserLogQueryDAO().queryBrowserErrorLogs(
+ serviceId, serviceVersionId, pagePathId, pagePath, errorCategory, startSecondTB, endSecondTB,
+ page.getLimit(),
+ page.getFrom()
+ );
+ }
+}
diff --git a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/input/BrowserErrorLogQueryCondition.java
similarity index 56%
copy from test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java
copy to oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/input/BrowserErrorLogQueryCondition.java
index 6c35a88..441538f 100644
--- a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/input/BrowserErrorLogQueryCondition.java
@@ -6,23 +6,30 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* 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.
- *
*/
-package org.apache.skywalking.e2e.utils;
+package org.apache.skywalking.oap.server.core.query.input;
-import java.time.LocalDateTime;
-import java.time.ZoneOffset;
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.skywalking.oap.server.core.query.type.ErrorCategory;
+import org.apache.skywalking.oap.server.core.query.type.Pagination;
-public final class Times {
- public static LocalDateTime now() {
- return LocalDateTime.now(ZoneOffset.UTC);
- }
+@Setter
+@Getter
+public class BrowserErrorLogQueryCondition {
+ private String serviceId;
+ private String serviceVersionId;
+ private String pagePathId;
+ private String pagePath;
+ private ErrorCategory category;
+ private Duration queryDuration;
+ private Pagination paging;
}
diff --git a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/BrowserErrorLog.java
similarity index 57%
copy from test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java
copy to oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/BrowserErrorLog.java
index 6c35a88..5e73536 100644
--- a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/BrowserErrorLog.java
@@ -6,23 +6,33 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* 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.
- *
*/
-package org.apache.skywalking.e2e.utils;
+package org.apache.skywalking.oap.server.core.query.type;
-import java.time.LocalDateTime;
-import java.time.ZoneOffset;
+import lombok.Getter;
+import lombok.Setter;
-public final class Times {
- public static LocalDateTime now() {
- return LocalDateTime.now(ZoneOffset.UTC);
- }
+@Setter
+@Getter
+public class BrowserErrorLog {
+ private String service;
+ private String serviceVersion;
+ private Long time;
+ private String pagePath;
+ private ErrorCategory category;
+ private String grade;
+ private String message;
+ private Integer line;
+ private Integer col;
+ private String stack;
+ private String errorUrl;
+ private boolean firstReportedError;
}
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/BrowserErrorLogs.java
similarity index 65%
copy from oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
copy to oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/BrowserErrorLogs.java
index ba3facc..8108808 100644
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/BrowserErrorLogs.java
@@ -6,26 +6,29 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* 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.
- *
*/
-package org.apache.skywalking.oap.server.core;
+package org.apache.skywalking.oap.server.core.query.type;
-import org.junit.Assert;
-import org.junit.Test;
+import java.util.ArrayList;
+import java.util.List;
+import lombok.Getter;
+import lombok.Setter;
-public class CoreModuleTest {
- @Test
- public void testOpenServiceList() {
- CoreModule coreModule = new CoreModule();
+@Getter
+public class BrowserErrorLogs {
+ private final List<BrowserErrorLog> logs;
+ @Setter
+ private int total;
- Assert.assertEquals(31, coreModule.services().length);
+ public BrowserErrorLogs() {
+ this.logs = new ArrayList<>();
}
}
diff --git a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/ErrorCategory.java
similarity index 73%
copy from test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java
copy to oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/ErrorCategory.java
index 6c35a88..7da58f8 100644
--- a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/type/ErrorCategory.java
@@ -6,23 +6,23 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* 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.
- *
*/
-package org.apache.skywalking.e2e.utils;
-
-import java.time.LocalDateTime;
-import java.time.ZoneOffset;
+package org.apache.skywalking.oap.server.core.query.type;
-public final class Times {
- public static LocalDateTime now() {
- return LocalDateTime.now(ZoneOffset.UTC);
- }
+public enum ErrorCategory {
+ ALL,
+ AJAX,
+ RESOURCE,
+ VUE,
+ PROMISE,
+ JS,
+ UNKNOWN
}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/DefaultScopeDefine.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/DefaultScopeDefine.java
index e753c62..17bf1bb 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/DefaultScopeDefine.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/DefaultScopeDefine.java
@@ -69,6 +69,15 @@ public class DefaultScopeDefine {
public static final int UI_TEMPLATE = 32;
public static final int SERVICE_INSTANCE_JVM_THREAD = 33;
+ // browser
+ public static final int BROWSER_ERROR_LOG = 34;
+ public static final int BROWSER_APP_PERF = 35;
+ public static final int BROWSER_APP_PAGE_PERF = 36;
+ public static final int BROWSER_APP_SINGLE_VERSION_PERF = 37;
+ public static final int BROWSER_APP_TRAFFIC = 38;
+ public static final int BROWSER_APP_SINGLE_VERSION_TRAFFIC = 39;
+ public static final int BROWSER_APP_PAGE_TRAFFIC = 40;
+
/**
* Catalog of scope, the metrics processor could use this to group all generated metrics by oal rt.
*/
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/StorageModule.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/StorageModule.java
index 1b5b9cd..4f72c0c 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/StorageModule.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/StorageModule.java
@@ -25,6 +25,7 @@ import org.apache.skywalking.oap.server.core.storage.profile.IProfileTaskQueryDA
import org.apache.skywalking.oap.server.core.storage.profile.IProfileThreadSnapshotQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IAggregationQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IAlarmQueryDAO;
+import org.apache.skywalking.oap.server.core.storage.query.IBrowserLogQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.ILogQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IMetadataQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IMetricsQueryDAO;
@@ -63,7 +64,8 @@ public class StorageModule extends ModuleDefine {
IProfileTaskQueryDAO.class,
IProfileTaskLogQueryDAO.class,
IProfileThreadSnapshotQueryDAO.class,
- UITemplateManagementDAO.class
+ UITemplateManagementDAO.class,
+ IBrowserLogQueryDAO.class
};
}
}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/query/IBrowserLogQueryDAO.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/query/IBrowserLogQueryDAO.java
new file mode 100644
index 0000000..a96ec59
--- /dev/null
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/query/IBrowserLogQueryDAO.java
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.core.storage.query;
+
+import com.google.protobuf.InvalidProtocolBufferException;
+import java.io.IOException;
+import java.util.Base64;
+import org.apache.skywalking.oap.server.core.browser.source.BrowserErrorCategory;
+import org.apache.skywalking.oap.server.core.query.type.BrowserErrorLog;
+import org.apache.skywalking.oap.server.core.query.type.BrowserErrorLogs;
+import org.apache.skywalking.oap.server.core.query.type.ErrorCategory;
+import org.apache.skywalking.oap.server.library.module.Service;
+
+public interface IBrowserLogQueryDAO extends Service {
+ BrowserErrorLogs queryBrowserErrorLogs(String serviceId,
+ String serviceVersionId,
+ String pagePathId,
+ String pagePath,
+ BrowserErrorCategory category,
+ long startSecondTB,
+ long endSecondTB,
+ int limit,
+ int from) throws IOException;
+
+ /**
+ * Parser the raw error log.
+ */
+ default BrowserErrorLog parserDataBinary(
+ String dataBinaryBase64) {
+ try {
+ BrowserErrorLog log = new BrowserErrorLog();
+ org.apache.skywalking.apm.network.language.agent.v3.BrowserErrorLog browserErrorLog = org.apache.skywalking.apm.network.language.agent.v3.BrowserErrorLog
+ .parseFrom(Base64.getDecoder().decode(dataBinaryBase64));
+
+ log.setService(browserErrorLog.getService());
+ log.setServiceVersion(browserErrorLog.getServiceVersion());
+ log.setTime(browserErrorLog.getTime());
+ log.setPagePath(browserErrorLog.getPagePath());
+ log.setCategory(ErrorCategory.valueOf(browserErrorLog.getCategory().name().toUpperCase()));
+ log.setGrade(browserErrorLog.getGrade());
+ log.setMessage(browserErrorLog.getMessage());
+ log.setLine(browserErrorLog.getLine());
+ log.setCol(browserErrorLog.getCol());
+ log.setStack(browserErrorLog.getStack());
+ log.setErrorUrl(browserErrorLog.getErrorUrl());
+ log.setFirstReportedError(browserErrorLog.getFirstReportedError());
+
+ return log;
+ } catch (InvalidProtocolBufferException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
index ba3facc..7475364 100644
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
+++ b/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
@@ -26,6 +26,6 @@ public class CoreModuleTest {
public void testOpenServiceList() {
CoreModule coreModule = new CoreModule();
- Assert.assertEquals(31, coreModule.services().length);
+ Assert.assertEquals(32, coreModule.services().length);
}
}
diff --git a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/GraphQLQueryProvider.java b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/GraphQLQueryProvider.java
index 145559d..82c4d8c 100644
--- a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/GraphQLQueryProvider.java
+++ b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/GraphQLQueryProvider.java
@@ -23,6 +23,7 @@ import graphql.GraphQL;
import graphql.schema.GraphQLSchema;
import org.apache.skywalking.oap.query.graphql.resolver.AggregationQuery;
import org.apache.skywalking.oap.query.graphql.resolver.AlarmQuery;
+import org.apache.skywalking.oap.query.graphql.resolver.BrowserLogQuery;
import org.apache.skywalking.oap.query.graphql.resolver.HealthQuery;
import org.apache.skywalking.oap.query.graphql.resolver.LogQuery;
import org.apache.skywalking.oap.query.graphql.resolver.MetadataQuery;
@@ -72,48 +73,50 @@ public class GraphQLQueryProvider extends ModuleProvider {
@Override
public void prepare() throws ServiceNotProvidedException, ModuleStartException {
GraphQLSchema schema = SchemaParser.newParser()
- .file("query-protocol/common.graphqls")
- .resolvers(new Query(), new Mutation(), new HealthQuery(getManager()))
- .file("query-protocol/metadata.graphqls")
- .resolvers(new MetadataQuery(getManager()))
- .file("query-protocol/topology.graphqls")
- .resolvers(new TopologyQuery(getManager()))
- /**
- * Metrics v2 query protocol is an alternative metrics query(s) of original v1,
- * defined in the metric.graphql, top-n-records.graphqls, and aggregation.graphqls.
- */
- .file("query-protocol/metrics-v2.graphqls")
- .resolvers(new MetricsQuery(getManager()))
- ////////
- //Deprecated Queries
- ////////
- .file("query-protocol/metric.graphqls")
- .resolvers(new MetricQuery(getManager()))
- .file("query-protocol/aggregation.graphqls")
- .resolvers(new AggregationQuery(getManager()))
- .file("query-protocol/top-n-records.graphqls")
- .resolvers(new TopNRecordsQuery(getManager()))
- ////////
- .file("query-protocol/trace.graphqls")
- .resolvers(new TraceQuery(getManager()))
- .file("query-protocol/alarm.graphqls")
- .resolvers(new AlarmQuery(getManager()))
- .file("query-protocol/log.graphqls")
- .resolvers(new LogQuery(getManager()))
- .file("query-protocol/profile.graphqls")
- .resolvers(new ProfileQuery(getManager()), new ProfileMutation(getManager()))
- .file("query-protocol/ui-configuration.graphqls")
- .resolvers(new UIConfigurationManagement(getManager()))
- .build()
- .makeExecutableSchema();
+ .file("query-protocol/common.graphqls")
+ .resolvers(new Query(), new Mutation(), new HealthQuery(getManager()))
+ .file("query-protocol/metadata.graphqls")
+ .resolvers(new MetadataQuery(getManager()))
+ .file("query-protocol/topology.graphqls")
+ .resolvers(new TopologyQuery(getManager()))
+ /**
+ * Metrics v2 query protocol is an alternative metrics query(s) of original v1,
+ * defined in the metric.graphql, top-n-records.graphqls, and aggregation.graphqls.
+ */
+ .file("query-protocol/metrics-v2.graphqls")
+ .resolvers(new MetricsQuery(getManager()))
+ ////////
+ //Deprecated Queries
+ ////////
+ .file("query-protocol/metric.graphqls")
+ .resolvers(new MetricQuery(getManager()))
+ .file("query-protocol/aggregation.graphqls")
+ .resolvers(new AggregationQuery(getManager()))
+ .file("query-protocol/top-n-records.graphqls")
+ .resolvers(new TopNRecordsQuery(getManager()))
+ ////////
+ .file("query-protocol/trace.graphqls")
+ .resolvers(new TraceQuery(getManager()))
+ .file("query-protocol/alarm.graphqls")
+ .resolvers(new AlarmQuery(getManager()))
+ .file("query-protocol/log.graphqls")
+ .resolvers(new LogQuery(getManager()))
+ .file("query-protocol/profile.graphqls")
+ .resolvers(new ProfileQuery(getManager()), new ProfileMutation(getManager()))
+ .file("query-protocol/ui-configuration.graphqls")
+ .resolvers(new UIConfigurationManagement(getManager()))
+ .file("query-protocol/browser-log.graphqls")
+ .resolvers(new BrowserLogQuery(getManager()))
+ .build()
+ .makeExecutableSchema();
this.graphQL = GraphQL.newGraphQL(schema).build();
}
@Override
public void start() throws ServiceNotProvidedException, ModuleStartException {
JettyHandlerRegister service = getManager().find(CoreModule.NAME)
- .provider()
- .getService(JettyHandlerRegister.class);
+ .provider()
+ .getService(JettyHandlerRegister.class);
service.addHandler(new GraphQLQueryHandler(config.getPath(), graphQL));
}
diff --git a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/BrowserLogQuery.java b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/BrowserLogQuery.java
new file mode 100644
index 0000000..3298f12
--- /dev/null
+++ b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/BrowserLogQuery.java
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.query.graphql.resolver;
+
+import com.coxautodev.graphql.tools.GraphQLQueryResolver;
+import java.io.IOException;
+import java.util.Optional;
+import lombok.RequiredArgsConstructor;
+import org.apache.skywalking.oap.server.core.CoreModule;
+import org.apache.skywalking.oap.server.core.query.BrowserLogQueryService;
+import org.apache.skywalking.oap.server.core.query.input.BrowserErrorLogQueryCondition;
+import org.apache.skywalking.oap.server.core.query.type.BrowserErrorLogs;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
+
+import static java.util.Objects.nonNull;
+
+@RequiredArgsConstructor
+public class BrowserLogQuery implements GraphQLQueryResolver {
+ private final ModuleManager moduleManager;
+ private BrowserLogQueryService queryService;
+
+ private BrowserLogQueryService getQueryService() {
+ return Optional.ofNullable(queryService).orElseGet(() -> {
+ queryService = moduleManager.find(CoreModule.NAME).provider().getService(BrowserLogQueryService.class);
+ return queryService;
+ });
+ }
+
+ public BrowserErrorLogs queryBrowserErrorLogs(BrowserErrorLogQueryCondition condition) throws IOException {
+ long startSecondTB = 0, endSecondTB = 0;
+ if (nonNull(condition.getQueryDuration())) {
+ startSecondTB = condition.getQueryDuration()
+ .getStartTimeBucketInSec();
+ endSecondTB = condition.getQueryDuration()
+ .getEndTimeBucketInSec();
+ }
+
+ return getQueryService().queryBrowserErrorLogs(
+ condition.getServiceId(), condition.getServiceVersionId(), condition.getPagePathId(),
+ condition.getPagePath(), condition.getCategory()
+ , startSecondTB, endSecondTB, condition.getPaging()
+ );
+ }
+}
diff --git a/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol b/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol
index 5ecefdf..92f62f1 160000
--- a/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol
+++ b/oap-server/server-query-plugin/query-graphql-plugin/src/main/resources/query-protocol
@@ -1 +1 @@
-Subproject commit 5ecefdf2c16ca16d4973806bdd26f9eafa3faf1d
+Subproject commit 92f62f13be3a2bf3dfd007ee85c68d54af2c6149
diff --git a/oap-server/server-receiver-plugin/pom.xml b/oap-server/server-receiver-plugin/pom.xml
index 50b0394..3483578 100644
--- a/oap-server/server-receiver-plugin/pom.xml
+++ b/oap-server/server-receiver-plugin/pom.xml
@@ -42,6 +42,7 @@
<module>skywalking-profile-receiver-plugin</module>
<module>opencensus-receiver-plugin</module>
<module>skywalking-meter-receiver-plugin</module>
+ <module>skywalking-browser-receiver-plugin</module>
</modules>
<dependencies>
diff --git a/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/pom.xml b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/pom.xml
new file mode 100644
index 0000000..f35587a
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/pom.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ ~ The ASF licenses this file to You under the Apache License, Version 2.0
+ ~ (the "License"); you may not use this file except in compliance with
+ ~ the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ 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.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>server-receiver-plugin</artifactId>
+ <groupId>org.apache.skywalking</groupId>
+ <version>8.2.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>skywalking-browser-receiver-plugin</artifactId>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.skywalking</groupId>
+ <artifactId>skywalking-sharing-server-plugin</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+</project>
\ No newline at end of file
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/module/BrowserModule.java
similarity index 64%
copy from oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
copy to oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/module/BrowserModule.java
index ba3facc..7e3d3b8 100644
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
+++ b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/module/BrowserModule.java
@@ -6,26 +6,28 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* 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.
- *
*/
-package org.apache.skywalking.oap.server.core;
+package org.apache.skywalking.oap.server.receiver.browser.module;
+
+import org.apache.skywalking.oap.server.library.module.ModuleDefine;
-import org.junit.Assert;
-import org.junit.Test;
+public class BrowserModule extends ModuleDefine {
+ private static final String NAME = "receiver-browser";
-public class CoreModuleTest {
- @Test
- public void testOpenServiceList() {
- CoreModule coreModule = new CoreModule();
+ public BrowserModule() {
+ super(NAME);
+ }
- Assert.assertEquals(31, coreModule.services().length);
+ @Override
+ public Class[] services() {
+ return new Class[0];
}
}
diff --git a/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/BrowserModuleProvider.java b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/BrowserModuleProvider.java
new file mode 100644
index 0000000..bc58caf
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/BrowserModuleProvider.java
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.receiver.browser.provider;
+
+import org.apache.skywalking.oap.server.configuration.api.ConfigurationModule;
+import org.apache.skywalking.oap.server.core.CoreModule;
+import org.apache.skywalking.oap.server.core.oal.rt.OALEngineLoaderService;
+import org.apache.skywalking.oap.server.core.server.GRPCHandlerRegister;
+import org.apache.skywalking.oap.server.library.module.ModuleConfig;
+import org.apache.skywalking.oap.server.library.module.ModuleDefine;
+import org.apache.skywalking.oap.server.library.module.ModuleProvider;
+import org.apache.skywalking.oap.server.library.module.ModuleStartException;
+import org.apache.skywalking.oap.server.library.module.ServiceNotProvidedException;
+import org.apache.skywalking.oap.server.receiver.browser.module.BrowserModule;
+import org.apache.skywalking.oap.server.receiver.browser.provider.handler.BrowserPerfServiceHandler;
+import org.apache.skywalking.oap.server.receiver.browser.provider.parser.errorlog.ErrorLogParserListenerManager;
+import org.apache.skywalking.oap.server.receiver.browser.provider.parser.errorlog.listener.ErrorLogRecordListener;
+import org.apache.skywalking.oap.server.receiver.browser.provider.parser.errorlog.listener.MultiScopesErrorLogAnalysisListener;
+import org.apache.skywalking.oap.server.receiver.browser.provider.parser.performance.PerfDataParserListenerManager;
+import org.apache.skywalking.oap.server.receiver.browser.provider.parser.performance.listener.MultiScopesPerfDataAnalysisListener;
+import org.apache.skywalking.oap.server.receiver.sharing.server.SharingServerModule;
+import org.apache.skywalking.oap.server.telemetry.TelemetryModule;
+
+public class BrowserModuleProvider extends ModuleProvider {
+ private final BrowserServiceModuleConfig moduleConfig = new BrowserServiceModuleConfig();
+
+ @Override
+ public String name() {
+ return "default";
+ }
+
+ @Override
+ public Class<? extends ModuleDefine> module() {
+ return BrowserModule.class;
+ }
+
+ @Override
+ public ModuleConfig createConfigBeanIfAbsent() {
+ return moduleConfig;
+ }
+
+ @Override
+ public void prepare() throws ServiceNotProvidedException, ModuleStartException {
+
+ }
+
+ @Override
+ public void start() throws ServiceNotProvidedException, ModuleStartException {
+ // load browser analysis
+ getManager().find(CoreModule.NAME)
+ .provider()
+ .getService(OALEngineLoaderService.class)
+ .load(BrowserOALDefine.INSTANCE);
+
+ GRPCHandlerRegister grpcHandlerRegister = getManager().find(SharingServerModule.NAME)
+ .provider().getService(GRPCHandlerRegister.class);
+
+ grpcHandlerRegister.addHandler(
+ new BrowserPerfServiceHandler(
+ getManager(), moduleConfig, perfDataListenerManager(), errorLogListenerManager()));
+ }
+
+ @Override
+ public void notifyAfterCompleted() throws ServiceNotProvidedException, ModuleStartException {
+
+ }
+
+ @Override
+ public String[] requiredModules() {
+ return new String[] {
+ TelemetryModule.NAME,
+ CoreModule.NAME,
+ SharingServerModule.NAME,
+ ConfigurationModule.NAME
+ };
+ }
+
+ private PerfDataParserListenerManager perfDataListenerManager() {
+ PerfDataParserListenerManager listenerManager = new PerfDataParserListenerManager();
+ listenerManager.add(new MultiScopesPerfDataAnalysisListener.Factory(getManager(), moduleConfig));
+
+ return listenerManager;
+ }
+
+ private ErrorLogParserListenerManager errorLogListenerManager() {
+ ErrorLogParserListenerManager listenerManager = new ErrorLogParserListenerManager();
+ listenerManager.add(new MultiScopesErrorLogAnalysisListener.Factory(getManager(), moduleConfig));
+ listenerManager.add(new ErrorLogRecordListener.Factory(getManager(), moduleConfig));
+
+ return listenerManager;
+ }
+}
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/BrowserOALDefine.java
similarity index 58%
copy from oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
copy to oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/BrowserOALDefine.java
index ba3facc..aebc9d4 100644
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
+++ b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/BrowserOALDefine.java
@@ -6,26 +6,29 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* 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.
- *
*/
-package org.apache.skywalking.oap.server.core;
+package org.apache.skywalking.oap.server.receiver.browser.provider;
-import org.junit.Assert;
-import org.junit.Test;
+import org.apache.skywalking.oap.server.core.oal.rt.OALDefine;
-public class CoreModuleTest {
- @Test
- public void testOpenServiceList() {
- CoreModule coreModule = new CoreModule();
+/**
+ * Browser OAL script includes the metrics related to browser only.
+ */
+public class BrowserOALDefine extends OALDefine {
+ public static final BrowserOALDefine INSTANCE = new BrowserOALDefine();
- Assert.assertEquals(31, coreModule.services().length);
+ private BrowserOALDefine() {
+ super(
+ "oal/browser.oal",
+ "org.apache.skywalking.oap.server.core.browser.source"
+ );
}
}
diff --git a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/BrowserServiceModuleConfig.java
similarity index 62%
copy from test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java
copy to oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/BrowserServiceModuleConfig.java
index 6c35a88..7d9974f 100644
--- a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java
+++ b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/BrowserServiceModuleConfig.java
@@ -6,23 +6,26 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* 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.
- *
*/
-package org.apache.skywalking.e2e.utils;
+package org.apache.skywalking.oap.server.receiver.browser.provider;
-import java.time.LocalDateTime;
-import java.time.ZoneOffset;
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.skywalking.oap.server.library.module.ModuleConfig;
-public final class Times {
- public static LocalDateTime now() {
- return LocalDateTime.now(ZoneOffset.UTC);
- }
+public class BrowserServiceModuleConfig extends ModuleConfig {
+ /**
+ * The sample rate precision is 1/10000. 10000 means 100% sample in default.
+ */
+ @Setter
+ @Getter
+ private int sampleRate = 10000;
}
diff --git a/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/handler/BrowserPerfServiceHandler.java b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/handler/BrowserPerfServiceHandler.java
new file mode 100644
index 0000000..3b1f633
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/handler/BrowserPerfServiceHandler.java
@@ -0,0 +1,144 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.receiver.browser.provider.handler;
+
+import io.grpc.stub.StreamObserver;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.apm.network.common.v3.Commands;
+import org.apache.skywalking.apm.network.language.agent.v3.BrowserErrorLog;
+import org.apache.skywalking.apm.network.language.agent.v3.BrowserPerfData;
+import org.apache.skywalking.apm.network.language.agent.v3.BrowserPerfServiceGrpc;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
+import org.apache.skywalking.oap.server.library.server.grpc.GRPCHandler;
+import org.apache.skywalking.oap.server.receiver.browser.provider.BrowserServiceModuleConfig;
+import org.apache.skywalking.oap.server.receiver.browser.provider.parser.errorlog.ErrorLogAnalyzer;
+import org.apache.skywalking.oap.server.receiver.browser.provider.parser.errorlog.ErrorLogParserListenerManager;
+import org.apache.skywalking.oap.server.receiver.browser.provider.parser.performance.PerfDataAnalyzer;
+import org.apache.skywalking.oap.server.receiver.browser.provider.parser.performance.PerfDataParserListenerManager;
+import org.apache.skywalking.oap.server.telemetry.TelemetryModule;
+import org.apache.skywalking.oap.server.telemetry.api.CounterMetrics;
+import org.apache.skywalking.oap.server.telemetry.api.HistogramMetrics;
+import org.apache.skywalking.oap.server.telemetry.api.MetricsCreator;
+import org.apache.skywalking.oap.server.telemetry.api.MetricsTag;
+
+/**
+ * Collect and process the performance and error log.
+ */
+@Slf4j
+public class BrowserPerfServiceHandler extends BrowserPerfServiceGrpc.BrowserPerfServiceImplBase implements GRPCHandler {
+ private final ModuleManager moduleManager;
+ private final BrowserServiceModuleConfig config;
+ private final PerfDataParserListenerManager perfDataListenerManager;
+ private final ErrorLogParserListenerManager errorLogListenerManager;
+
+ // performance
+ private final HistogramMetrics perfHistogram;
+ private final CounterMetrics perfErrorCounter;
+
+ // error log
+ private final HistogramMetrics errorLogHistogram;
+ private final CounterMetrics logErrorCounter;
+
+ public BrowserPerfServiceHandler(ModuleManager moduleManager,
+ BrowserServiceModuleConfig config,
+ PerfDataParserListenerManager perfDataListenerManager,
+ ErrorLogParserListenerManager errorLogListenerManager) {
+ this.moduleManager = moduleManager;
+ this.config = config;
+ this.perfDataListenerManager = perfDataListenerManager;
+ this.errorLogListenerManager = errorLogListenerManager;
+
+ MetricsCreator metricsCreator = moduleManager.find(TelemetryModule.NAME)
+ .provider()
+ .getService(MetricsCreator.class);
+
+ // performance
+ perfHistogram = metricsCreator.createHistogramMetric(
+ "browser_perf_data_in_latency", "The process latency of browser performance data",
+ new MetricsTag.Keys("protocol"), new MetricsTag.Values("grpc")
+ );
+ perfErrorCounter = metricsCreator.createCounter(
+ "browser_perf_data_analysis_error_count", "The error number of browser performance data analysis",
+ new MetricsTag.Keys("protocol"), new MetricsTag.Values("grpc")
+ );
+
+ // error log
+ errorLogHistogram = metricsCreator.createHistogramMetric(
+ "browser_error_log_in_latency", "The process latency of browser error log", new MetricsTag.Keys("protocol"),
+ new MetricsTag.Values("grpc")
+ );
+ logErrorCounter = metricsCreator.createCounter(
+ "browser_error_log_analysis_error_count", "The error number of browser error log analysis",
+ new MetricsTag.Keys("protocol"), new MetricsTag.Values("grpc")
+ );
+ }
+
+ @Override
+ public void collectPerfData(final BrowserPerfData request, final StreamObserver<Commands> responseObserver) {
+ if (log.isDebugEnabled()) {
+ log.debug("receive browser performance data");
+ }
+ HistogramMetrics.Timer timer = perfHistogram.createTimer();
+ try {
+ PerfDataAnalyzer analyzer = new PerfDataAnalyzer(moduleManager, perfDataListenerManager, config);
+ analyzer.doAnalysis(request);
+ } catch (Throwable e) {
+ log.error(e.getMessage(), e);
+ perfErrorCounter.inc();
+ } finally {
+ timer.finish();
+ responseObserver.onNext(Commands.newBuilder().build());
+ responseObserver.onCompleted();
+ }
+ }
+
+ @Override
+ public StreamObserver<BrowserErrorLog> collectErrorLogs(final StreamObserver<Commands> responseObserver) {
+ return new StreamObserver<BrowserErrorLog>() {
+ @Override
+ public void onNext(final BrowserErrorLog browserErrorLog) {
+ if (log.isDebugEnabled()) {
+ log.debug("receive browser error log");
+ }
+
+ HistogramMetrics.Timer timer = errorLogHistogram.createTimer();
+ try {
+ ErrorLogAnalyzer analyzer = new ErrorLogAnalyzer(moduleManager, errorLogListenerManager, config);
+ analyzer.doAnalysis(browserErrorLog);
+ } catch (Throwable e) {
+ log.error(e.getMessage(), e);
+ logErrorCounter.inc();
+ } finally {
+ timer.finish();
+ }
+ }
+
+ @Override
+ public void onError(final Throwable throwable) {
+ log.error(throwable.getMessage(), throwable);
+ responseObserver.onCompleted();
+ }
+
+ @Override
+ public void onCompleted() {
+ responseObserver.onNext(Commands.newBuilder().build());
+ responseObserver.onCompleted();
+ }
+ };
+ }
+}
diff --git a/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/errorlog/BrowserErrorLogDecorator.java b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/errorlog/BrowserErrorLogDecorator.java
new file mode 100644
index 0000000..56785fd
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/errorlog/BrowserErrorLogDecorator.java
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.receiver.browser.provider.parser.errorlog;
+
+import lombok.RequiredArgsConstructor;
+import org.apache.skywalking.apm.network.language.agent.v3.BrowserErrorLog;
+import org.apache.skywalking.apm.network.language.agent.v3.ErrorCategory;
+
+@RequiredArgsConstructor
+public class BrowserErrorLogDecorator {
+ private boolean isOrigin = true;
+ private final BrowserErrorLog errorLog;
+ private BrowserErrorLog.Builder builder;
+
+ public String getUniqueId() {
+ return isOrigin ? errorLog.getUniqueId() : builder.getUniqueId();
+ }
+
+ public String getService() {
+ return isOrigin ? errorLog.getService() : builder.getService();
+ }
+
+ public String getServiceVersion() {
+ return isOrigin ? errorLog.getServiceVersion() : builder.getServiceVersion();
+ }
+
+ public long getTime() {
+ return isOrigin ? errorLog.getTime() : builder.getTime();
+ }
+
+ public String getPagePath() {
+ return isOrigin ? errorLog.getPagePath() : builder.getPagePath();
+ }
+
+ public ErrorCategory getCategory() {
+ return isOrigin ? errorLog.getCategory() : builder.getCategory();
+ }
+
+ public String getGrade() {
+ return isOrigin ? errorLog.getGrade() : builder.getGrade();
+ }
+
+ public String getMessage() {
+ return isOrigin ? errorLog.getMessage() : builder.getMessage();
+ }
+
+ public int getLine() {
+ return isOrigin ? errorLog.getLine() : builder.getLine();
+ }
+
+ public int getCol() {
+ return isOrigin ? errorLog.getCol() : builder.getCol();
+ }
+
+ public String getStack() {
+ return isOrigin ? errorLog.getStack() : builder.getStack();
+ }
+
+ public String getErrorUrl() {
+ return isOrigin ? errorLog.getErrorUrl() : builder.getErrorUrl();
+ }
+
+ public boolean isFirstReportedError() {
+ return isOrigin ? errorLog.getFirstReportedError() : builder.getFirstReportedError();
+ }
+
+ public byte[] toByteArray() {
+ return isOrigin ? errorLog.toByteArray() : builder.build().toByteArray();
+ }
+
+ public void setTime(long time) {
+ if (isOrigin) {
+ toBuilder();
+ }
+ builder.setTime(time);
+ }
+
+ void toBuilder() {
+ if (isOrigin) {
+ this.isOrigin = false;
+ this.builder = errorLog.toBuilder();
+ }
+ }
+}
diff --git a/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/errorlog/ErrorLogAnalyzer.java b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/errorlog/ErrorLogAnalyzer.java
new file mode 100644
index 0000000..d56763f
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/errorlog/ErrorLogAnalyzer.java
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.receiver.browser.provider.parser.errorlog;
+
+import java.util.LinkedList;
+import java.util.List;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.apm.network.language.agent.v3.BrowserErrorLog;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
+import org.apache.skywalking.oap.server.receiver.browser.provider.BrowserServiceModuleConfig;
+import org.apache.skywalking.oap.server.receiver.browser.provider.parser.errorlog.listener.ErrorLogAnalysisListener;
+
+@Slf4j
+@RequiredArgsConstructor
+public class ErrorLogAnalyzer {
+ private final ModuleManager moduleManager;
+ private final ErrorLogParserListenerManager listenerManager;
+ private final BrowserServiceModuleConfig moduleConfig;
+
+ private final List<ErrorLogAnalysisListener> analysisListeners = new LinkedList<>();
+
+ public void doAnalysis(BrowserErrorLog errorLog) {
+ createAnalysisListeners();
+
+ try {
+ BrowserErrorLogDecorator decorator = new BrowserErrorLogDecorator(errorLog);
+ // Use the server side current time.
+ long nowMillis = System.currentTimeMillis();
+ decorator.setTime(nowMillis);
+
+ notifyListener(decorator);
+
+ notifyListenerToBuild();
+ } catch (Throwable e) {
+ log.error(e.getMessage(), e);
+ }
+ }
+
+ private void notifyListener(BrowserErrorLogDecorator decorator) {
+ analysisListeners.forEach(listener -> listener.parse(decorator));
+ }
+
+ private void notifyListenerToBuild() {
+ analysisListeners.forEach(ErrorLogAnalysisListener::build);
+ }
+
+ private void createAnalysisListeners() {
+ listenerManager.getErrorLogAnalysisListeners()
+ .forEach(factory -> analysisListeners.add(factory.create(moduleManager, moduleConfig)));
+ }
+}
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/errorlog/ErrorLogParserListenerManager.java
similarity index 56%
copy from oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
copy to oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/errorlog/ErrorLogParserListenerManager.java
index ba3facc..f7aea0f 100644
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
+++ b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/errorlog/ErrorLogParserListenerManager.java
@@ -6,26 +6,27 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* 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.
- *
*/
-package org.apache.skywalking.oap.server.core;
+package org.apache.skywalking.oap.server.receiver.browser.provider.parser.errorlog;
-import org.junit.Assert;
-import org.junit.Test;
+import java.util.LinkedList;
+import java.util.List;
+import lombok.Getter;
+import org.apache.skywalking.oap.server.receiver.browser.provider.parser.errorlog.listener.ErrorLogListenerFactory;
-public class CoreModuleTest {
- @Test
- public void testOpenServiceList() {
- CoreModule coreModule = new CoreModule();
+public class ErrorLogParserListenerManager {
+ @Getter
+ private final List<ErrorLogListenerFactory> errorLogAnalysisListeners = new LinkedList<>();
- Assert.assertEquals(31, coreModule.services().length);
+ public void add(final ErrorLogListenerFactory factory) {
+ errorLogAnalysisListeners.add(factory);
}
}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/expression/InMatch.java b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/errorlog/listener/ErrorLogAnalysisListener.java
similarity index 53%
copy from oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/expression/InMatch.java
copy to oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/errorlog/listener/ErrorLogAnalysisListener.java
index 2873f3d..4fdd98a 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/expression/InMatch.java
+++ b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/errorlog/listener/ErrorLogAnalysisListener.java
@@ -15,26 +15,22 @@
* limitations under the License.
*/
-package org.apache.skywalking.oap.server.core.analysis.metrics.expression;
+package org.apache.skywalking.oap.server.receiver.browser.provider.parser.errorlog.listener;
-import java.util.Objects;
-import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.FilterMatcher;
+import org.apache.skywalking.oap.server.receiver.browser.provider.parser.errorlog.BrowserErrorLogDecorator;
-@FilterMatcher
-public class InMatch {
+/**
+ * ErrorLogAnalysisListener represents the callback when OAP does the browser error log analysis.
+ */
+public interface ErrorLogAnalysisListener {
+ /**
+ * The last step of the analysis process. Typically, the implementations forward the analysis results to the source
+ * receiver.
+ */
+ void build();
- public boolean match(Object left, Object[] rights) {
- for (Object right : rights) {
- if (right instanceof String) {
- String r = (String) right;
- if (r.startsWith("\"") && r.endsWith("\"")) {
- right = r.substring(1, r.length() - 1);
- }
- }
- if (Objects.equals(left, right)) {
- return true;
- }
- }
- return false;
- }
+ /**
+ * Parse the raw data from the probe (js-client).
+ */
+ void parse(BrowserErrorLogDecorator decorator);
}
diff --git a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/errorlog/listener/ErrorLogListenerFactory.java
similarity index 61%
copy from test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java
copy to oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/errorlog/listener/ErrorLogListenerFactory.java
index 6c35a88..d13bfd6 100644
--- a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java
+++ b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/errorlog/listener/ErrorLogListenerFactory.java
@@ -6,23 +6,20 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* 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.
- *
*/
-package org.apache.skywalking.e2e.utils;
+package org.apache.skywalking.oap.server.receiver.browser.provider.parser.errorlog.listener;
-import java.time.LocalDateTime;
-import java.time.ZoneOffset;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
+import org.apache.skywalking.oap.server.receiver.browser.provider.BrowserServiceModuleConfig;
-public final class Times {
- public static LocalDateTime now() {
- return LocalDateTime.now(ZoneOffset.UTC);
- }
+public interface ErrorLogListenerFactory {
+ ErrorLogAnalysisListener create(final ModuleManager moduleManager, final BrowserServiceModuleConfig moduleConfig);
}
diff --git a/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/errorlog/listener/ErrorLogRecordListener.java b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/errorlog/listener/ErrorLogRecordListener.java
new file mode 100644
index 0000000..216875d
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/errorlog/listener/ErrorLogRecordListener.java
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.receiver.browser.provider.parser.errorlog.listener;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.apm.util.StringUtil;
+import org.apache.skywalking.oap.server.core.CoreModule;
+import org.apache.skywalking.oap.server.core.analysis.IDManager;
+import org.apache.skywalking.oap.server.core.analysis.NodeType;
+import org.apache.skywalking.oap.server.core.analysis.TimeBucket;
+import org.apache.skywalking.oap.server.core.browser.source.BrowserErrorCategory;
+import org.apache.skywalking.oap.server.core.browser.source.BrowserErrorLog;
+import org.apache.skywalking.oap.server.core.config.NamingControl;
+import org.apache.skywalking.oap.server.core.source.SourceReceiver;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
+import org.apache.skywalking.oap.server.receiver.browser.provider.BrowserServiceModuleConfig;
+import org.apache.skywalking.oap.server.receiver.browser.provider.parser.errorlog.BrowserErrorLogDecorator;
+
+/**
+ * ErrorLogRecordListener forwards the error log raw data to the persistence layer with the query required conditions.
+ */
+@Slf4j
+@RequiredArgsConstructor
+public class ErrorLogRecordListener implements ErrorLogAnalysisListener {
+ private final NamingControl namingControl;
+ private final SourceReceiver sourceReceiver;
+ private final BrowserErrorLog errorLog = new BrowserErrorLog();
+ private final ErrorLogRecordSampler sampler;
+ private SampleStatus sampleStatus = SampleStatus.UNKNOWN;
+
+ /**
+ * Send BrowserErrorLog to the oreceiver.
+ */
+ @Override
+ public void build() {
+ if (sampleStatus.equals(SampleStatus.SAMPLED)) {
+ sourceReceiver.receive(errorLog);
+ }
+ }
+
+ @Override
+ public void parse(final BrowserErrorLogDecorator decorator) {
+ // sample
+ if (StringUtil.isEmpty(decorator.getUniqueId())) {
+ if (log.isDebugEnabled()) {
+ log.debug("Because uniqueId is empty BrowserErrorLog is ignored.");
+ }
+ sampleStatus = SampleStatus.IGNORED;
+ return;
+ }
+
+ if (!sampler.shouldSample(decorator.getUniqueId().hashCode())) {
+ sampleStatus = SampleStatus.IGNORED;
+ return;
+ }
+ sampleStatus = SampleStatus.SAMPLED;
+
+ // error log
+ errorLog.setUniqueId(decorator.getUniqueId());
+ errorLog.setTimeBucket(TimeBucket.getRecordTimeBucket(decorator.getTime()));
+ errorLog.setTimestamp(decorator.getTime());
+
+ // service
+ String serviceName = namingControl.formatServiceName(decorator.getService());
+ errorLog.setServiceId(IDManager.ServiceID.buildId(serviceName, NodeType.Browser));
+
+ // service version
+ String serviceVersionName = namingControl.formatInstanceName(decorator.getServiceVersion());
+ errorLog.setServiceVersionId(IDManager.ServiceInstanceID.buildId(serviceName, serviceVersionName));
+
+ // page
+ String pagePath = namingControl.formatEndpointName(serviceName, decorator.getPagePath());
+ errorLog.setPagePath(pagePath);
+ errorLog.setPagePathId(IDManager.EndpointID.buildId(serviceName, pagePath));
+
+ // raw data
+ errorLog.setErrorCategory(BrowserErrorCategory.fromErrorCategory(decorator.getCategory()));
+ errorLog.setDataBinary(decorator.toByteArray());
+ }
+
+ private enum SampleStatus {
+ UNKNOWN, SAMPLED, IGNORED
+ }
+
+ public static class Factory implements ErrorLogListenerFactory {
+ private final SourceReceiver sourceReceiver;
+ private final NamingControl namingControl;
+ private final ErrorLogRecordSampler sampler;
+
+ public Factory(ModuleManager moduleManager, BrowserServiceModuleConfig moduleConfig) {
+ this.sourceReceiver = moduleManager.find(CoreModule.NAME).provider().getService(SourceReceiver.class);
+ this.namingControl = moduleManager.find(CoreModule.NAME).provider().getService(NamingControl.class);
+ this.sampler = new ErrorLogRecordSampler(moduleConfig.getSampleRate());
+ }
+
+ @Override
+ public ErrorLogAnalysisListener create(final ModuleManager moduleManager,
+ final BrowserServiceModuleConfig moduleConfig) {
+ return new ErrorLogRecordListener(namingControl, sourceReceiver, sampler);
+ }
+ }
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/expression/InMatch.java b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/errorlog/listener/ErrorLogRecordSampler.java
similarity index 54%
copy from oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/expression/InMatch.java
copy to oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/errorlog/listener/ErrorLogRecordSampler.java
index 2873f3d..5e825b7 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/expression/InMatch.java
+++ b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/errorlog/listener/ErrorLogRecordSampler.java
@@ -15,26 +15,24 @@
* limitations under the License.
*/
-package org.apache.skywalking.oap.server.core.analysis.metrics.expression;
+package org.apache.skywalking.oap.server.receiver.browser.provider.parser.errorlog.listener;
-import java.util.Objects;
-import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.FilterMatcher;
+import lombok.RequiredArgsConstructor;
+import org.apache.skywalking.apm.network.language.agent.v3.BrowserErrorLog;
-@FilterMatcher
-public class InMatch {
+/**
+ * The sampler makes the sampling mechanism works at backend side. Sample result: [0,sampleRate) sampled, (sampleRate,~)
+ * ignored
+ */
+@RequiredArgsConstructor
+public class ErrorLogRecordSampler {
+ private final int sampleRate;
- public boolean match(Object left, Object[] rights) {
- for (Object right : rights) {
- if (right instanceof String) {
- String r = (String) right;
- if (r.startsWith("\"") && r.endsWith("\"")) {
- right = r.substring(1, r.length() - 1);
- }
- }
- if (Objects.equals(left, right)) {
- return true;
- }
- }
- return false;
+ /**
+ * through {@link BrowserErrorLog#getUniqueId()} hash code.
+ */
+ public boolean shouldSample(int hashCode) {
+ return hashCode % 10000 < sampleRate;
}
+
}
diff --git a/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/errorlog/listener/MultiScopesErrorLogAnalysisListener.java b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/errorlog/listener/MultiScopesErrorLogAnalysisListener.java
new file mode 100644
index 0000000..30ef1f3
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/errorlog/listener/MultiScopesErrorLogAnalysisListener.java
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.receiver.browser.provider.parser.errorlog.listener;
+
+import org.apache.skywalking.oap.server.core.CoreModule;
+import org.apache.skywalking.oap.server.core.analysis.TimeBucket;
+import org.apache.skywalking.oap.server.core.browser.source.BrowserAppTrafficCategory;
+import org.apache.skywalking.oap.server.core.config.NamingControl;
+import org.apache.skywalking.oap.server.core.source.SourceReceiver;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
+import org.apache.skywalking.oap.server.receiver.browser.provider.BrowserServiceModuleConfig;
+import org.apache.skywalking.oap.server.receiver.browser.provider.parser.errorlog.BrowserErrorLogDecorator;
+
+/**
+ * MultiScopesErrorLogAnalysisListener analysis error log, the kinds of error and error sum metrics.
+ */
+public class MultiScopesErrorLogAnalysisListener implements ErrorLogAnalysisListener {
+ private final SourceReceiver sourceReceiver;
+
+ private final SourceBuilder sourceBuilder;
+
+ public MultiScopesErrorLogAnalysisListener(final SourceReceiver sourceReceiver, final NamingControl namingControl) {
+ this.sourceReceiver = sourceReceiver;
+ this.sourceBuilder = new SourceBuilder(namingControl);
+ }
+
+ /**
+ * Send BrowserAppTraffic, BrowserAppSingleVersionTraffic, BrowserAppPageTraffic and BrowserAppPagePerf scope to the
+ * receiver.
+ */
+ @Override
+ public void build() {
+ sourceReceiver.receive(sourceBuilder.toBrowserAppTraffic());
+ sourceReceiver.receive(sourceBuilder.toBrowserAppSingleVersionTraffic());
+ sourceReceiver.receive(sourceBuilder.toBrowserAppPageTraffic());
+ }
+
+ @Override
+ public void parse(final BrowserErrorLogDecorator decorator) {
+ sourceBuilder.setService(decorator.getService());
+ sourceBuilder.setServiceVersion(decorator.getServiceVersion());
+ sourceBuilder.setPatePath(decorator.getPagePath());
+
+ // time bucket
+ sourceBuilder.setTimeBucket(TimeBucket.getMinuteTimeBucket(decorator.getTime()));
+
+ // category
+ sourceBuilder.setTrafficCategory(
+ decorator.isFirstReportedError() ? BrowserAppTrafficCategory.FIRST_ERROR : BrowserAppTrafficCategory.ERROR);
+ sourceBuilder.setErrorCategory(decorator.getCategory());
+ }
+
+ public static class Factory implements ErrorLogListenerFactory {
+ private final SourceReceiver sourceReceiver;
+ private final NamingControl namingControl;
+
+ public Factory(ModuleManager moduleManager, BrowserServiceModuleConfig moduleConfig) {
+ this.sourceReceiver = moduleManager.find(CoreModule.NAME).provider().getService(SourceReceiver.class);
+ this.namingControl = moduleManager.find(CoreModule.NAME).provider().getService(NamingControl.class);
+ }
+
+ @Override
+ public ErrorLogAnalysisListener create(final ModuleManager moduleManager,
+ final BrowserServiceModuleConfig moduleConfig) {
+ return new MultiScopesErrorLogAnalysisListener(sourceReceiver, namingControl);
+ }
+ }
+}
diff --git a/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/errorlog/listener/SourceBuilder.java b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/errorlog/listener/SourceBuilder.java
new file mode 100644
index 0000000..4541a5f
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/errorlog/listener/SourceBuilder.java
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.receiver.browser.provider.parser.errorlog.listener;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.Setter;
+import org.apache.skywalking.apm.network.language.agent.v3.ErrorCategory;
+import org.apache.skywalking.oap.server.core.browser.source.BrowserAppPageTraffic;
+import org.apache.skywalking.oap.server.core.browser.source.BrowserAppSingleVersionTraffic;
+import org.apache.skywalking.oap.server.core.browser.source.BrowserAppTraffic;
+import org.apache.skywalking.oap.server.core.browser.source.BrowserAppTrafficCategory;
+import org.apache.skywalking.oap.server.core.browser.source.BrowserAppTrafficSource;
+import org.apache.skywalking.oap.server.core.browser.source.BrowserErrorCategory;
+import org.apache.skywalking.oap.server.core.config.NamingControl;
+
+@RequiredArgsConstructor
+class SourceBuilder {
+ private final NamingControl namingControl;
+
+ @Getter
+ private String service;
+
+ public void setService(final String service) {
+ this.service = namingControl.formatServiceName(service);
+ }
+
+ @Getter
+ private String serviceVersion;
+
+ public void setServiceVersion(final String serviceVersion) {
+ this.serviceVersion = namingControl.formatInstanceName(serviceVersion);
+ }
+
+ @Getter
+ private String patePath;
+
+ public void setPatePath(final String patePath) {
+ this.patePath = namingControl.formatEndpointName(service, patePath);
+ }
+
+ @Setter
+ @Getter
+ private long timeBucket;
+
+ @Setter
+ @Getter
+ private BrowserAppTrafficCategory trafficCategory;
+
+ @Setter
+ @Getter
+ private BrowserErrorCategory errorCategory;
+
+ public void setErrorCategory(ErrorCategory category) {
+ this.errorCategory = BrowserErrorCategory.fromErrorCategory(category);
+ }
+
+ private void toBrowserAppTrafficSource(BrowserAppTrafficSource source) {
+ source.setTimeBucket(timeBucket);
+ source.setTrafficCategory(trafficCategory);
+ source.setErrorCategory(errorCategory);
+ }
+
+ /**
+ * Browser service traffic error related source.
+ */
+ BrowserAppTraffic toBrowserAppTraffic() {
+ BrowserAppTraffic traffic = new BrowserAppTraffic();
+ toBrowserAppTrafficSource(traffic);
+ traffic.setName(service);
+ traffic.setTrafficCategory(trafficCategory);
+ traffic.setErrorCategory(errorCategory);
+ return traffic;
+ }
+
+ /**
+ * Browser single version error metrics related source.
+ */
+ BrowserAppSingleVersionTraffic toBrowserAppSingleVersionTraffic() {
+ BrowserAppSingleVersionTraffic traffic = new BrowserAppSingleVersionTraffic();
+ toBrowserAppTrafficSource(traffic);
+ traffic.setName(serviceVersion);
+ traffic.setServiceName(service);
+ return traffic;
+ }
+
+ /**
+ * Browser page error metrics related source.
+ */
+ BrowserAppPageTraffic toBrowserAppPageTraffic() {
+ BrowserAppPageTraffic traffic = new BrowserAppPageTraffic();
+ toBrowserAppTrafficSource(traffic);
+ traffic.setName(patePath);
+ traffic.setServiceName(service);
+ return traffic;
+ }
+}
diff --git a/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/performance/BrowserPerfDataDecorator.java b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/performance/BrowserPerfDataDecorator.java
new file mode 100644
index 0000000..f486375
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/performance/BrowserPerfDataDecorator.java
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.receiver.browser.provider.parser.performance;
+
+import lombok.RequiredArgsConstructor;
+import org.apache.skywalking.apm.network.language.agent.v3.BrowserPerfData;
+
+@RequiredArgsConstructor
+public class BrowserPerfDataDecorator {
+ private boolean isOrigin = true;
+ private final BrowserPerfData browserPerfData;
+ private BrowserPerfData.Builder builder;
+
+ public String getService() {
+ return isOrigin ? browserPerfData.getService() : builder.getService();
+ }
+
+ public String getServiceVersion() {
+ return isOrigin ? browserPerfData.getServiceVersion() : builder.getServiceVersion();
+ }
+
+ public long getTime() {
+ return isOrigin ? browserPerfData.getTime() : builder.getTime();
+ }
+
+ public String getPagePath() {
+ return isOrigin ? browserPerfData.getPagePath() : builder.getPagePath();
+ }
+
+ public int getRedirectTime() {
+ return isOrigin ? browserPerfData.getRedirectTime() : builder.getRedirectTime();
+ }
+
+ public int getDnsTime() {
+ return isOrigin ? browserPerfData.getDnsTime() : builder.getDnsTime();
+ }
+
+ public int getTtfbTime() {
+ return isOrigin ? browserPerfData.getTtfbTime() : builder.getTtfbTime();
+ }
+
+ public int getTcpTime() {
+ return isOrigin ? browserPerfData.getTcpTime() : builder.getTcpTime();
+ }
+
+ public int getTransTime() {
+ return isOrigin ? browserPerfData.getTransTime() : builder.getTransTime();
+ }
+
+ public int getDomAnalysisTime() {
+ return isOrigin ? browserPerfData.getDomAnalysisTime() : builder.getDomAnalysisTime();
+ }
+
+ public int getFptTime() {
+ return isOrigin ? browserPerfData.getFptTime() : builder.getFptTime();
+ }
+
+ public int getDomReadyTime() {
+ return isOrigin ? browserPerfData.getDomReadyTime() : builder.getDomReadyTime();
+ }
+
+ public int getLoadPageTime() {
+ return isOrigin ? browserPerfData.getLoadPageTime() : builder.getLoadPageTime();
+ }
+
+ public int getResTime() {
+ return isOrigin ? browserPerfData.getResTime() : builder.getResTime();
+ }
+
+ public int getSslTime() {
+ return isOrigin ? browserPerfData.getSslTime() : builder.getSslTime();
+ }
+
+ public int getTtlTime() {
+ return isOrigin ? browserPerfData.getTtlTime() : builder.getTtlTime();
+ }
+
+ public int getFirstPackTime() {
+ return isOrigin ? browserPerfData.getFirstPackTime() : builder.getFirstPackTime();
+ }
+
+ public int getFmpTime() {
+ return isOrigin ? browserPerfData.getFmpTime() : builder.getFmpTime();
+ }
+
+ public void setTime(long time) {
+ if (isOrigin) {
+ toBuilder();
+ }
+ builder.setTime(time);
+ }
+
+ void toBuilder() {
+ if (isOrigin) {
+ this.isOrigin = false;
+ this.builder = browserPerfData.toBuilder();
+ }
+ }
+}
diff --git a/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/performance/PerfDataAnalyzer.java b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/performance/PerfDataAnalyzer.java
new file mode 100644
index 0000000..ae66fe1
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/performance/PerfDataAnalyzer.java
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.receiver.browser.provider.parser.performance;
+
+import java.util.LinkedList;
+import java.util.List;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.apm.network.language.agent.v3.BrowserPerfData;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
+import org.apache.skywalking.oap.server.receiver.browser.provider.BrowserServiceModuleConfig;
+import org.apache.skywalking.oap.server.receiver.browser.provider.parser.performance.listener.PerfDataAnalysisListener;
+
+@Slf4j
+@RequiredArgsConstructor
+public class PerfDataAnalyzer {
+ private final ModuleManager moduleManager;
+ private final PerfDataParserListenerManager listenerManager;
+ private final BrowserServiceModuleConfig config;
+
+ private final List<PerfDataAnalysisListener> analysisListeners = new LinkedList<>();
+
+ public void doAnalysis(BrowserPerfData browserPerfData) {
+ createAnalysisListeners();
+
+ try {
+ BrowserPerfDataDecorator decorator = new BrowserPerfDataDecorator(browserPerfData);
+ // Use the server side current time.
+ long nowMillis = System.currentTimeMillis();
+ decorator.setTime(nowMillis);
+
+ notifyListener(decorator);
+
+ notifyListenerToBuild();
+ } catch (Throwable e) {
+ log.error(e.getMessage(), e);
+ }
+ }
+
+ private void notifyListener(BrowserPerfDataDecorator decorator) {
+ analysisListeners.forEach(listener -> listener.parse(decorator));
+ }
+
+ private void notifyListenerToBuild() {
+ analysisListeners.forEach(PerfDataAnalysisListener::build);
+ }
+
+ private void createAnalysisListeners() {
+ listenerManager.getPerfDataListenerFactories()
+ .forEach(factory -> analysisListeners.add(factory.create(moduleManager, config)));
+ }
+}
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/performance/PerfDataParserListenerManager.java
similarity index 56%
copy from oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
copy to oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/performance/PerfDataParserListenerManager.java
index ba3facc..1d369c2 100644
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
+++ b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/performance/PerfDataParserListenerManager.java
@@ -6,26 +6,27 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* 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.
- *
*/
-package org.apache.skywalking.oap.server.core;
+package org.apache.skywalking.oap.server.receiver.browser.provider.parser.performance;
-import org.junit.Assert;
-import org.junit.Test;
+import java.util.LinkedList;
+import java.util.List;
+import lombok.Getter;
+import org.apache.skywalking.oap.server.receiver.browser.provider.parser.performance.listener.PerfDataListenerFactory;
-public class CoreModuleTest {
- @Test
- public void testOpenServiceList() {
- CoreModule coreModule = new CoreModule();
+public class PerfDataParserListenerManager {
+ @Getter
+ private final List<PerfDataListenerFactory> perfDataListenerFactories = new LinkedList<>();
- Assert.assertEquals(31, coreModule.services().length);
+ public void add(final PerfDataListenerFactory factory) {
+ perfDataListenerFactories.add(factory);
}
}
diff --git a/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/performance/listener/MultiScopesPerfDataAnalysisListener.java b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/performance/listener/MultiScopesPerfDataAnalysisListener.java
new file mode 100644
index 0000000..4aed690
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/performance/listener/MultiScopesPerfDataAnalysisListener.java
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.receiver.browser.provider.parser.performance.listener;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.oap.server.core.CoreModule;
+import org.apache.skywalking.oap.server.core.analysis.TimeBucket;
+import org.apache.skywalking.oap.server.core.config.NamingControl;
+import org.apache.skywalking.oap.server.core.source.SourceReceiver;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
+import org.apache.skywalking.oap.server.receiver.browser.provider.BrowserServiceModuleConfig;
+import org.apache.skywalking.oap.server.receiver.browser.provider.parser.performance.BrowserPerfDataDecorator;
+
+/**
+ * Browser traffic and page Performance related metrics.
+ */
+@Slf4j
+public class MultiScopesPerfDataAnalysisListener implements PerfDataAnalysisListener {
+ private final SourceReceiver sourceReceiver;
+
+ private final SourceBuilder sourceBuilder;
+
+ public MultiScopesPerfDataAnalysisListener(final SourceReceiver sourceReceiver,
+ final NamingControl namingControl) {
+ this.sourceReceiver = sourceReceiver;
+ this.sourceBuilder = new SourceBuilder(namingControl);
+ }
+
+ /**
+ * Send BrowserAppTraffic, BrowserAppSingleVersionTraffic, BrowserAppPageTraffic and BrowserAppPagePerf scope to the
+ * receiver.
+ */
+ @Override
+ public void build() {
+ // traffic
+ sourceReceiver.receive(sourceBuilder.toBrowserAppTraffic());
+ sourceReceiver.receive(sourceBuilder.toBrowserAppSingleVersionTraffic());
+ sourceReceiver.receive(sourceBuilder.toBrowserAppPageTraffic());
+
+ // performance (currently only page level performance data is analyzed)
+ sourceReceiver.receive(sourceBuilder.toBrowserAppPagePerf());
+ }
+
+ /**
+ * Parse raw data
+ */
+ @Override
+ public void parse(final BrowserPerfDataDecorator decorator) {
+ sourceBuilder.setService(decorator.getService());
+ sourceBuilder.setServiceVersion(decorator.getServiceVersion());
+ sourceBuilder.setPatePath(decorator.getPagePath());
+
+ // time
+ sourceBuilder.setTimeBucket(TimeBucket.getMinuteTimeBucket(decorator.getTime()));
+
+ // performance related
+ sourceBuilder.setRedirectTime(decorator.getRedirectTime());
+ sourceBuilder.setDnsTime(decorator.getDnsTime());
+ sourceBuilder.setTtfbTime(decorator.getTtfbTime());
+ sourceBuilder.setTcpTime(decorator.getTcpTime());
+ sourceBuilder.setTransTime(decorator.getTransTime());
+ sourceBuilder.setDomAnalysisTime(decorator.getDomAnalysisTime());
+ sourceBuilder.setFptTime(decorator.getFptTime());
+ sourceBuilder.setDomReadyTime(decorator.getDomReadyTime());
+ sourceBuilder.setLoadPageTime(decorator.getLoadPageTime());
+ sourceBuilder.setResTime(decorator.getResTime());
+ sourceBuilder.setSslTime(decorator.getSslTime());
+ sourceBuilder.setTtlTime(decorator.getTtlTime());
+ sourceBuilder.setFirstPackTime(decorator.getFirstPackTime());
+ sourceBuilder.setFmpTime(decorator.getFmpTime());
+ }
+
+ public static class Factory implements PerfDataListenerFactory {
+
+ private final SourceReceiver sourceReceiver;
+ private final NamingControl namingControl;
+
+ public Factory(ModuleManager moduleManager, BrowserServiceModuleConfig moduleConfig) {
+ this.sourceReceiver = moduleManager.find(CoreModule.NAME)
+ .provider()
+ .getService(SourceReceiver.class);
+
+ this.namingControl = moduleManager.find(CoreModule.NAME)
+ .provider()
+ .getService(NamingControl.class);
+ }
+
+ @Override
+ public PerfDataAnalysisListener create(final ModuleManager moduleManager,
+ final BrowserServiceModuleConfig moduleConfig) {
+ return new MultiScopesPerfDataAnalysisListener(sourceReceiver, namingControl);
+ }
+ }
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/expression/InMatch.java b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/performance/listener/PerfDataAnalysisListener.java
similarity index 53%
copy from oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/expression/InMatch.java
copy to oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/performance/listener/PerfDataAnalysisListener.java
index 2873f3d..b5a4574 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/expression/InMatch.java
+++ b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/performance/listener/PerfDataAnalysisListener.java
@@ -15,26 +15,22 @@
* limitations under the License.
*/
-package org.apache.skywalking.oap.server.core.analysis.metrics.expression;
+package org.apache.skywalking.oap.server.receiver.browser.provider.parser.performance.listener;
-import java.util.Objects;
-import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.FilterMatcher;
+import org.apache.skywalking.oap.server.receiver.browser.provider.parser.performance.BrowserPerfDataDecorator;
-@FilterMatcher
-public class InMatch {
+/**
+ * BrowserPerfDataListener represents the callback when OAP does the browser performance data analysis.
+ */
+public interface PerfDataAnalysisListener {
+ /**
+ * The last step of the analysis process. Typically, the implementations forward the analysis results to the source
+ * receiver.
+ */
+ void build();
- public boolean match(Object left, Object[] rights) {
- for (Object right : rights) {
- if (right instanceof String) {
- String r = (String) right;
- if (r.startsWith("\"") && r.endsWith("\"")) {
- right = r.substring(1, r.length() - 1);
- }
- }
- if (Objects.equals(left, right)) {
- return true;
- }
- }
- return false;
- }
+ /**
+ * Parse the raw data from the probe (js-client).
+ */
+ void parse(BrowserPerfDataDecorator decorator);
}
diff --git a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/performance/listener/PerfDataListenerFactory.java
similarity index 54%
copy from test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java
copy to oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/performance/listener/PerfDataListenerFactory.java
index 6c35a88..24cd4e2 100644
--- a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java
+++ b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/performance/listener/PerfDataListenerFactory.java
@@ -6,23 +6,24 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* 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.
- *
*/
-package org.apache.skywalking.e2e.utils;
+package org.apache.skywalking.oap.server.receiver.browser.provider.parser.performance.listener;
-import java.time.LocalDateTime;
-import java.time.ZoneOffset;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
+import org.apache.skywalking.oap.server.receiver.browser.provider.BrowserServiceModuleConfig;
-public final class Times {
- public static LocalDateTime now() {
- return LocalDateTime.now(ZoneOffset.UTC);
- }
+/**
+ * BrowserPerfDataListenerFactory implementation creates the listener instances when required. Every
+ * BrowserPerfDataListener could have its own creation factory.
+ */
+public interface PerfDataListenerFactory {
+ PerfDataAnalysisListener create(ModuleManager moduleManager, BrowserServiceModuleConfig moduleConfig);
}
diff --git a/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/performance/listener/SourceBuilder.java b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/performance/listener/SourceBuilder.java
new file mode 100644
index 0000000..7d50ea4
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/browser/provider/parser/performance/listener/SourceBuilder.java
@@ -0,0 +1,201 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.receiver.browser.provider.parser.performance.listener;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.Setter;
+import org.apache.skywalking.oap.server.core.browser.source.BrowserAppPagePerf;
+import org.apache.skywalking.oap.server.core.browser.source.BrowserAppPageTraffic;
+import org.apache.skywalking.oap.server.core.browser.source.BrowserAppPerf;
+import org.apache.skywalking.oap.server.core.browser.source.BrowserAppPerfSource;
+import org.apache.skywalking.oap.server.core.browser.source.BrowserAppSingleVersionPerf;
+import org.apache.skywalking.oap.server.core.browser.source.BrowserAppSingleVersionTraffic;
+import org.apache.skywalking.oap.server.core.browser.source.BrowserAppTraffic;
+import org.apache.skywalking.oap.server.core.browser.source.BrowserAppTrafficCategory;
+import org.apache.skywalking.oap.server.core.browser.source.BrowserAppTrafficSource;
+import org.apache.skywalking.oap.server.core.config.NamingControl;
+import org.apache.skywalking.oap.server.core.source.Source;
+
+/**
+ * Browser traffic and performance related source.
+ */
+@RequiredArgsConstructor
+class SourceBuilder {
+ private final NamingControl namingControl;
+
+ @Getter
+ private String service;
+
+ public void setService(final String service) {
+ this.service = namingControl.formatServiceName(service);
+ }
+
+ @Getter
+ private String serviceVersion;
+
+ public void setServiceVersion(final String serviceVersion) {
+ this.serviceVersion = namingControl.formatInstanceName(serviceVersion);
+ }
+
+ @Getter
+ private String patePath;
+
+ public void setPatePath(final String patePath) {
+ this.patePath = namingControl.formatEndpointName(service, patePath);
+ }
+
+ @Setter
+ @Getter
+ private long timeBucket;
+
+ // performance data detail
+ @Setter
+ @Getter
+ private int redirectTime;
+ @Setter
+ @Getter
+ private int dnsTime;
+ @Setter
+ @Getter
+ private int ttfbTime;
+ @Setter
+ @Getter
+ private int tcpTime;
+ @Setter
+ @Getter
+ private int transTime;
+ @Setter
+ @Getter
+ private int domAnalysisTime;
+ @Setter
+ @Getter
+ private int fptTime;
+ @Setter
+ @Getter
+ private int domReadyTime;
+ @Setter
+ @Getter
+ private int loadPageTime;
+ @Setter
+ @Getter
+ private int resTime;
+ @Setter
+ @Getter
+ private int sslTime;
+ @Setter
+ @Getter
+ private int ttlTime;
+ @Setter
+ @Getter
+ private int firstPackTime;
+ @Setter
+ @Getter
+ private int fmpTime;
+
+ private void toSource(Source source) {
+ source.setTimeBucket(timeBucket);
+ }
+
+ private void toBrowserAppTrafficSource(BrowserAppTrafficSource source) {
+ toSource(source);
+ source.setTrafficCategory(BrowserAppTrafficCategory.NORMAL);
+ }
+
+ /**
+ * Browser service meta and traffic metrics related source.
+ */
+ BrowserAppTraffic toBrowserAppTraffic() {
+ BrowserAppTraffic traffic = new BrowserAppTraffic();
+ traffic.setName(service);
+ toBrowserAppTrafficSource(traffic);
+ return traffic;
+ }
+
+ /**
+ * Browser single version meta and traffic metrics related source.
+ */
+ BrowserAppSingleVersionTraffic toBrowserAppSingleVersionTraffic() {
+ BrowserAppSingleVersionTraffic traffic = new BrowserAppSingleVersionTraffic();
+ traffic.setName(serviceVersion);
+ traffic.setServiceName(service);
+ toBrowserAppTrafficSource(traffic);
+ return traffic;
+ }
+
+ /**
+ * Browser page meta and traffic metrics related source.
+ */
+ BrowserAppPageTraffic toBrowserAppPageTraffic() {
+ BrowserAppPageTraffic traffic = new BrowserAppPageTraffic();
+ traffic.setName(patePath);
+ traffic.setServiceName(service);
+ toBrowserAppTrafficSource(traffic);
+ return traffic;
+ }
+
+ private void toBrowserAppPerfSource(BrowserAppPerfSource source) {
+ toSource(source);
+ source.setRedirectTime(redirectTime);
+ source.setDnsTime(dnsTime);
+ source.setTtfbTime(ttfbTime);
+ source.setTcpTime(tcpTime);
+ source.setTransTime(transTime);
+ source.setDomAnalysisTime(domAnalysisTime);
+ source.setFptTime(fptTime);
+ source.setDomReadyTime(domReadyTime);
+ source.setLoadPageTime(loadPageTime);
+ source.setResTime(resTime);
+ source.setSslTime(sslTime);
+ source.setTtlTime(ttlTime);
+ source.setFirstPackTime(firstPackTime);
+ source.setFmpTime(fmpTime);
+ }
+
+ /**
+ * Browser service performance related source.
+ */
+ BrowserAppPerf toBrowserAppPerf() {
+ BrowserAppPerf perf = new BrowserAppPerf();
+ perf.setName(service);
+ toBrowserAppPerfSource(perf);
+ return perf;
+ }
+
+ /**
+ * Browser single version performance related source.
+ */
+ BrowserAppSingleVersionPerf toBrowserAppSingleVersionPerf() {
+ BrowserAppSingleVersionPerf perf = new BrowserAppSingleVersionPerf();
+ perf.setName(serviceVersion);
+ perf.setServiceName(service);
+ toBrowserAppPerfSource(perf);
+ return perf;
+ }
+
+ /**
+ * Browser page performance related source.
+ */
+ BrowserAppPagePerf toBrowserAppPagePerf() {
+ BrowserAppPagePerf perf = new BrowserAppPagePerf();
+ perf.setName(patePath);
+ perf.setServiceName(service);
+ toBrowserAppPerfSource(perf);
+ return perf;
+ }
+}
diff --git a/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleDefine b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleDefine
new file mode 100644
index 0000000..9c91d56
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleDefine
@@ -0,0 +1,19 @@
+#
+# 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.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# 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.
+#
+#
+
+org.apache.skywalking.oap.server.receiver.browser.module.BrowserModule
\ No newline at end of file
diff --git a/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider
new file mode 100644
index 0000000..2f2efd0
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-browser-receiver-plugin/src/main/resources/META-INF/services/org.apache.skywalking.oap.server.library.module.ModuleProvider
@@ -0,0 +1,19 @@
+#
+# 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.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# 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.
+#
+#
+
+org.apache.skywalking.oap.server.receiver.browser.provider.BrowserModuleProvider
\ No newline at end of file
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/StorageModuleElasticsearchProvider.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/StorageModuleElasticsearchProvider.java
index 030b965..5515e3d 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/StorageModuleElasticsearchProvider.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/StorageModuleElasticsearchProvider.java
@@ -42,6 +42,7 @@ import org.apache.skywalking.oap.server.core.storage.profile.IProfileTaskQueryDA
import org.apache.skywalking.oap.server.core.storage.profile.IProfileThreadSnapshotQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IAggregationQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IAlarmQueryDAO;
+import org.apache.skywalking.oap.server.core.storage.query.IBrowserLogQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.ILogQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IMetadataQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IMetricsQueryDAO;
@@ -64,6 +65,7 @@ import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.TimeSe
import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.cache.NetworkAddressAliasEsDAO;
import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.AggregationQueryEsDAO;
import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.AlarmQueryEsDAO;
+import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.BrowserLogQueryEsDAO;
import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.LogQueryEsDAO;
import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.MetadataQueryEsDAO;
import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.MetricsQueryEsDAO;
@@ -168,6 +170,7 @@ public class StorageModuleElasticsearchProvider extends ModuleProvider {
this.registerServiceImplementation(IMetricsQueryDAO.class, new MetricsQueryEsDAO(elasticSearchClient));
this.registerServiceImplementation(
ITraceQueryDAO.class, new TraceQueryEsDAO(elasticSearchClient, config.getSegmentQueryMaxSize()));
+ this.registerServiceImplementation(IBrowserLogQueryDAO.class, new BrowserLogQueryEsDAO(elasticSearchClient));
this.registerServiceImplementation(
IMetadataQueryDAO.class, new MetadataQueryEsDAO(elasticSearchClient, config.getMetadataQueryMaxSize()));
this.registerServiceImplementation(IAggregationQueryDAO.class, new AggregationQueryEsDAO(elasticSearchClient));
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/BrowserLogQueryEsDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/BrowserLogQueryEsDAO.java
new file mode 100644
index 0000000..daa0ed9
--- /dev/null
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/BrowserLogQueryEsDAO.java
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query;
+
+import com.google.common.base.Strings;
+import java.io.IOException;
+import org.apache.skywalking.apm.util.StringUtil;
+import org.apache.skywalking.oap.server.core.browser.manual.errorlog.BrowserErrorLogRecord;
+import org.apache.skywalking.oap.server.core.browser.source.BrowserErrorCategory;
+import org.apache.skywalking.oap.server.core.query.type.BrowserErrorLog;
+import org.apache.skywalking.oap.server.core.query.type.BrowserErrorLogs;
+import org.apache.skywalking.oap.server.core.storage.query.IBrowserLogQueryDAO;
+import org.apache.skywalking.oap.server.library.client.elasticsearch.ElasticSearchClient;
+import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.EsDAO;
+import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.MatchCNameBuilder;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.index.query.BoolQueryBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.search.SearchHit;
+import org.elasticsearch.search.builder.SearchSourceBuilder;
+
+import static java.util.Objects.nonNull;
+
+public class BrowserLogQueryEsDAO extends EsDAO implements IBrowserLogQueryDAO {
+ public BrowserLogQueryEsDAO(final ElasticSearchClient client) {
+ super(client);
+ }
+
+ @Override
+ public BrowserErrorLogs queryBrowserErrorLogs(final String serviceId,
+ final String serviceVersionId,
+ final String pagePathId,
+ final String pagePath,
+ final BrowserErrorCategory category,
+ final long startSecondTB,
+ final long endSecondTB,
+ final int limit,
+ final int from) throws IOException {
+ SearchSourceBuilder sourceBuilder = SearchSourceBuilder.searchSource();
+
+ BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
+ sourceBuilder.query(boolQueryBuilder);
+
+ if (startSecondTB != 0 && endSecondTB != 0) {
+ boolQueryBuilder.must().add(
+ QueryBuilders.rangeQuery(BrowserErrorLogRecord.TIME_BUCKET).gte(startSecondTB).lte(endSecondTB));
+ }
+
+ if (!Strings.isNullOrEmpty(pagePath)) {
+ String matchCName = MatchCNameBuilder.INSTANCE.build(BrowserErrorLogRecord.PAGE_PATH);
+ boolQueryBuilder.must().add(QueryBuilders.matchPhraseQuery(matchCName, pagePath));
+ }
+ if (StringUtil.isNotEmpty(serviceId)) {
+ boolQueryBuilder.must().add(QueryBuilders.termQuery(BrowserErrorLogRecord.SERVICE_ID, serviceId));
+ }
+ if (StringUtil.isNotEmpty(serviceVersionId)) {
+ boolQueryBuilder.must()
+ .add(QueryBuilders.termQuery(BrowserErrorLogRecord.SERVICE_VERSION_ID, serviceVersionId));
+ }
+ if (StringUtil.isNotEmpty(pagePathId)) {
+ boolQueryBuilder.must().add(QueryBuilders.termQuery(BrowserErrorLogRecord.PAGE_PATH_ID, pagePathId));
+ }
+ if (nonNull(category)) {
+ boolQueryBuilder.must()
+ .add(QueryBuilders.termQuery(BrowserErrorLogRecord.ERROR_CATEGORY, category.getValue()));
+ }
+ sourceBuilder.size(limit);
+ sourceBuilder.from(from);
+
+ SearchResponse response = getClient().search(BrowserErrorLogRecord.INDEX_NAME, sourceBuilder);
+
+ BrowserErrorLogs logs = new BrowserErrorLogs();
+ logs.setTotal((int) response.getHits().totalHits);
+
+ for (SearchHit searchHit : response.getHits().getHits()) {
+ String dataBinaryBase64 = (String) searchHit.getSourceAsMap().get(BrowserErrorLogRecord.DATA_BINARY);
+ if (nonNull(dataBinaryBase64)) {
+ BrowserErrorLog log = parserDataBinary(dataBinaryBase64);
+ logs.getLogs().add(log);
+ }
+ }
+ return logs;
+ }
+}
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/StorageModuleElasticsearch7Provider.java b/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/StorageModuleElasticsearch7Provider.java
index 414946f..9acab87 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/StorageModuleElasticsearch7Provider.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/StorageModuleElasticsearch7Provider.java
@@ -40,6 +40,7 @@ import org.apache.skywalking.oap.server.core.storage.profile.IProfileTaskQueryDA
import org.apache.skywalking.oap.server.core.storage.profile.IProfileThreadSnapshotQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IAggregationQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IAlarmQueryDAO;
+import org.apache.skywalking.oap.server.core.storage.query.IBrowserLogQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.ILogQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IMetadataQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IMetricsQueryDAO;
@@ -66,6 +67,7 @@ import org.apache.skywalking.oap.server.storage.plugin.elasticsearch7.client.Ela
import org.apache.skywalking.oap.server.storage.plugin.elasticsearch7.dao.StorageEs7DAO;
import org.apache.skywalking.oap.server.storage.plugin.elasticsearch7.query.AggregationQueryEs7DAO;
import org.apache.skywalking.oap.server.storage.plugin.elasticsearch7.query.AlarmQueryEs7DAO;
+import org.apache.skywalking.oap.server.storage.plugin.elasticsearch7.query.BrowserLogQueryEs7DAO;
import org.apache.skywalking.oap.server.storage.plugin.elasticsearch7.query.LogQueryEs7DAO;
import org.apache.skywalking.oap.server.storage.plugin.elasticsearch7.query.MetadataQueryEs7DAO;
import org.apache.skywalking.oap.server.storage.plugin.elasticsearch7.query.MetricsQueryEs7DAO;
@@ -120,7 +122,7 @@ public class StorageModuleElasticsearch7Provider extends ModuleProvider {
}
if (!StringUtil.isEmpty(config.getSecretsManagementFile())) {
MultipleFilesChangeMonitor monitor = new MultipleFilesChangeMonitor(
- 10, readableContents -> {
+ 10, readableContents -> {
final byte[] secretsFileContent = readableContents.get(0);
if (secretsFileContent == null) {
return;
@@ -148,58 +150,62 @@ public class StorageModuleElasticsearch7Provider extends ModuleProvider {
}
elasticSearch7Client = new ElasticSearch7Client(
- config.getClusterNodes(), config.getProtocol(), config.getTrustStorePath(), config
- .getTrustStorePass(), config.getUser(), config.getPassword(),
- indexNameConverters(config.getNameSpace())
+ config.getClusterNodes(), config.getProtocol(), config.getTrustStorePath(), config
+ .getTrustStorePass(), config.getUser(), config.getPassword(),
+ indexNameConverters(config.getNameSpace())
);
this.registerServiceImplementation(
- IBatchDAO.class, new BatchProcessEsDAO(elasticSearch7Client, config.getBulkActions(),
- config.getFlushInterval(), config.getConcurrentRequests()
- ));
+ IBatchDAO.class, new BatchProcessEsDAO(elasticSearch7Client, config.getBulkActions(),
+ config.getFlushInterval(), config.getConcurrentRequests()
+ ));
this.registerServiceImplementation(StorageDAO.class, new StorageEs7DAO(elasticSearch7Client));
this.registerServiceImplementation(
- IHistoryDeleteDAO.class, new HistoryDeleteEsDAO(elasticSearch7Client));
+ IHistoryDeleteDAO.class, new HistoryDeleteEsDAO(elasticSearch7Client));
this.registerServiceImplementation(
- INetworkAddressAliasDAO.class, new NetworkAddressAliasEsDAO(
- elasticSearch7Client,
- config.getResultWindowMaxSize()
- ));
+ INetworkAddressAliasDAO.class, new NetworkAddressAliasEsDAO(
+ elasticSearch7Client,
+ config.getResultWindowMaxSize()
+ ));
this.registerServiceImplementation(ITopologyQueryDAO.class, new TopologyQueryEsDAO(elasticSearch7Client));
this.registerServiceImplementation(IMetricsQueryDAO.class, new MetricsQueryEs7DAO(elasticSearch7Client));
this.registerServiceImplementation(
- ITraceQueryDAO.class, new TraceQueryEs7DAO(elasticSearch7Client, config.getSegmentQueryMaxSize()));
+ ITraceQueryDAO.class, new TraceQueryEs7DAO(elasticSearch7Client, config.getSegmentQueryMaxSize()));
+ this.registerServiceImplementation(IBrowserLogQueryDAO.class, new BrowserLogQueryEs7DAO(elasticSearch7Client));
this.registerServiceImplementation(
- IMetadataQueryDAO.class, new MetadataQueryEs7DAO(elasticSearch7Client, config.getMetadataQueryMaxSize()));
+ IMetadataQueryDAO.class, new MetadataQueryEs7DAO(elasticSearch7Client, config.getMetadataQueryMaxSize()));
this.registerServiceImplementation(
- IAggregationQueryDAO.class, new AggregationQueryEs7DAO(elasticSearch7Client));
+ IAggregationQueryDAO.class, new AggregationQueryEs7DAO(elasticSearch7Client));
this.registerServiceImplementation(IAlarmQueryDAO.class, new AlarmQueryEs7DAO(elasticSearch7Client));
this.registerServiceImplementation(ITopNRecordsQueryDAO.class, new TopNRecordsQueryEsDAO(elasticSearch7Client));
this.registerServiceImplementation(ILogQueryDAO.class, new LogQueryEs7DAO(elasticSearch7Client));
this.registerServiceImplementation(
- IProfileTaskQueryDAO.class, new ProfileTaskQueryEsDAO(
- elasticSearch7Client,
- config.getProfileTaskQueryMaxSize()
- ));
+ IProfileTaskQueryDAO.class, new ProfileTaskQueryEsDAO(
+ elasticSearch7Client,
+ config.getProfileTaskQueryMaxSize()
+ ));
this.registerServiceImplementation(
- IProfileTaskLogQueryDAO.class, new ProfileTaskLogEsDAO(
- elasticSearch7Client,
- config.getProfileTaskQueryMaxSize()
- ));
+ IProfileTaskLogQueryDAO.class, new ProfileTaskLogEsDAO(
+ elasticSearch7Client,
+ config.getProfileTaskQueryMaxSize()
+ ));
this.registerServiceImplementation(
- IProfileThreadSnapshotQueryDAO.class, new ProfileThreadSnapshotQueryEs7DAO(
- elasticSearch7Client,
- config.getProfileTaskQueryMaxSize()
- ));
+ IProfileThreadSnapshotQueryDAO.class, new ProfileThreadSnapshotQueryEs7DAO(
+ elasticSearch7Client,
+ config.getProfileTaskQueryMaxSize()
+ ));
this.registerServiceImplementation(
- UITemplateManagementDAO.class, new UITemplateManagementEsDAO(elasticSearch7Client));
+ UITemplateManagementDAO.class, new UITemplateManagementEsDAO(elasticSearch7Client));
}
@Override
public void start() throws ModuleStartException {
- MetricsCreator metricCreator = getManager().find(TelemetryModule.NAME).provider().getService(MetricsCreator.class);
- HealthCheckMetrics healthChecker = metricCreator.createHealthCheckerGauge("storage_elasticsearch", MetricsTag.EMPTY_KEY, MetricsTag.EMPTY_VALUE);
+ MetricsCreator metricCreator = getManager().find(TelemetryModule.NAME)
+ .provider()
+ .getService(MetricsCreator.class);
+ HealthCheckMetrics healthChecker = metricCreator.createHealthCheckerGauge(
+ "storage_elasticsearch", MetricsTag.EMPTY_KEY, MetricsTag.EMPTY_VALUE);
elasticSearch7Client.registerChecker(healthChecker);
try {
elasticSearch7Client.connect();
@@ -217,6 +223,6 @@ public class StorageModuleElasticsearch7Provider extends ModuleProvider {
@Override
public String[] requiredModules() {
- return new String[]{CoreModule.NAME};
+ return new String[] {CoreModule.NAME};
}
}
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/query/BrowserLogQueryEs7DAO.java b/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/query/BrowserLogQueryEs7DAO.java
new file mode 100644
index 0000000..2f10c49
--- /dev/null
+++ b/oap-server/server-storage-plugin/storage-elasticsearch7-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch7/query/BrowserLogQueryEs7DAO.java
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.storage.plugin.elasticsearch7.query;
+
+import com.google.common.base.Strings;
+import java.io.IOException;
+import org.apache.skywalking.apm.util.StringUtil;
+import org.apache.skywalking.oap.server.core.browser.manual.errorlog.BrowserErrorLogRecord;
+import org.apache.skywalking.oap.server.core.browser.source.BrowserErrorCategory;
+import org.apache.skywalking.oap.server.core.query.type.BrowserErrorLog;
+import org.apache.skywalking.oap.server.core.query.type.BrowserErrorLogs;
+import org.apache.skywalking.oap.server.library.client.elasticsearch.ElasticSearchClient;
+import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.base.MatchCNameBuilder;
+import org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.BrowserLogQueryEsDAO;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.index.query.BoolQueryBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.search.SearchHit;
+import org.elasticsearch.search.builder.SearchSourceBuilder;
+
+import static java.util.Objects.nonNull;
+
+public class BrowserLogQueryEs7DAO extends BrowserLogQueryEsDAO {
+ public BrowserLogQueryEs7DAO(final ElasticSearchClient client) {
+ super(client);
+ }
+
+ @Override
+ public BrowserErrorLogs queryBrowserErrorLogs(final String serviceId,
+ final String serviceVersionId,
+ final String pagePathId,
+ final String pagePath,
+ final BrowserErrorCategory category,
+ final long startSecondTB,
+ final long endSecondTB,
+ final int limit,
+ final int from) throws IOException {
+ SearchSourceBuilder sourceBuilder = SearchSourceBuilder.searchSource();
+
+ BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
+ sourceBuilder.query(boolQueryBuilder);
+
+ if (startSecondTB != 0 && endSecondTB != 0) {
+ boolQueryBuilder.must().add(
+ QueryBuilders.rangeQuery(BrowserErrorLogRecord.TIME_BUCKET).gte(startSecondTB).lte(endSecondTB));
+ }
+
+ if (!Strings.isNullOrEmpty(pagePath)) {
+ String matchCName = MatchCNameBuilder.INSTANCE.build(BrowserErrorLogRecord.PAGE_PATH);
+ boolQueryBuilder.must().add(QueryBuilders.matchPhraseQuery(matchCName, pagePath));
+ }
+ if (StringUtil.isNotEmpty(serviceId)) {
+ boolQueryBuilder.must().add(QueryBuilders.termQuery(BrowserErrorLogRecord.SERVICE_ID, serviceId));
+ }
+ if (StringUtil.isNotEmpty(serviceVersionId)) {
+ boolQueryBuilder.must()
+ .add(QueryBuilders.termQuery(BrowserErrorLogRecord.SERVICE_VERSION_ID, serviceVersionId));
+ }
+ if (StringUtil.isNotEmpty(pagePathId)) {
+ boolQueryBuilder.must().add(QueryBuilders.termQuery(BrowserErrorLogRecord.PAGE_PATH_ID, pagePathId));
+ }
+ if (nonNull(category)) {
+ boolQueryBuilder.must()
+ .add(QueryBuilders.termQuery(BrowserErrorLogRecord.ERROR_CATEGORY, category.getValue()));
+ }
+ sourceBuilder.size(limit);
+ sourceBuilder.from(from);
+
+ SearchResponse response = getClient().search(BrowserErrorLogRecord.INDEX_NAME, sourceBuilder);
+
+ BrowserErrorLogs logs = new BrowserErrorLogs();
+ logs.setTotal((int) response.getHits().getTotalHits().value);
+
+ for (SearchHit searchHit : response.getHits().getHits()) {
+ String dataBinaryBase64 = (String) searchHit.getSourceAsMap().get(BrowserErrorLogRecord.DATA_BINARY);
+ if (nonNull(dataBinaryBase64)) {
+ BrowserErrorLog log = parserDataBinary(dataBinaryBase64);
+ logs.getLogs().add(log);
+ }
+ }
+ return logs;
+ }
+}
diff --git a/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/InfluxStorageProvider.java b/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/InfluxStorageProvider.java
index 13d7eda..c4e32e2 100644
--- a/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/InfluxStorageProvider.java
+++ b/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/InfluxStorageProvider.java
@@ -33,6 +33,7 @@ import org.apache.skywalking.oap.server.core.storage.profile.IProfileTaskQueryDA
import org.apache.skywalking.oap.server.core.storage.profile.IProfileThreadSnapshotQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IAggregationQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IAlarmQueryDAO;
+import org.apache.skywalking.oap.server.core.storage.query.IBrowserLogQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.ILogQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IMetadataQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IMetricsQueryDAO;
@@ -49,6 +50,7 @@ import org.apache.skywalking.oap.server.storage.plugin.influxdb.base.HistoryDele
import org.apache.skywalking.oap.server.storage.plugin.influxdb.base.InfluxStorageDAO;
import org.apache.skywalking.oap.server.storage.plugin.influxdb.query.AggregationQuery;
import org.apache.skywalking.oap.server.storage.plugin.influxdb.query.AlarmQuery;
+import org.apache.skywalking.oap.server.storage.plugin.influxdb.query.BrowserLogQuery;
import org.apache.skywalking.oap.server.storage.plugin.influxdb.query.LogQuery;
import org.apache.skywalking.oap.server.storage.plugin.influxdb.query.MetadataQuery;
import org.apache.skywalking.oap.server.storage.plugin.influxdb.query.MetricsQuery;
@@ -98,6 +100,7 @@ public class InfluxStorageProvider extends ModuleProvider {
this.registerServiceImplementation(ITopologyQueryDAO.class, new TopologyQuery(client));
this.registerServiceImplementation(IMetricsQueryDAO.class, new MetricsQuery(client));
this.registerServiceImplementation(ITraceQueryDAO.class, new TraceQuery(client));
+ this.registerServiceImplementation(IBrowserLogQueryDAO.class, new BrowserLogQuery(client));
this.registerServiceImplementation(IAggregationQueryDAO.class, new AggregationQuery(client));
this.registerServiceImplementation(IAlarmQueryDAO.class, new AlarmQuery(client));
this.registerServiceImplementation(ITopNRecordsQueryDAO.class, new TopNRecordsQuery(client));
@@ -105,12 +108,12 @@ public class InfluxStorageProvider extends ModuleProvider {
this.registerServiceImplementation(IProfileTaskQueryDAO.class, new ProfileTaskQuery(client));
this.registerServiceImplementation(
- IProfileThreadSnapshotQueryDAO.class, new ProfileThreadSnapshotQuery(client));
+ IProfileThreadSnapshotQueryDAO.class, new ProfileThreadSnapshotQuery(client));
this.registerServiceImplementation(
- IProfileTaskLogQueryDAO.class, new ProfileTaskLogQuery(client, config.getFetchTaskLogMaxSize()));
+ IProfileTaskLogQueryDAO.class, new ProfileTaskLogQuery(client, config.getFetchTaskLogMaxSize()));
this.registerServiceImplementation(
- IHistoryDeleteDAO.class, new HistoryDeleteDAO(client));
+ IHistoryDeleteDAO.class, new HistoryDeleteDAO(client));
this.registerServiceImplementation(UITemplateManagementDAO.class, new UITemplateManagementDAOImpl(client));
}
@@ -133,6 +136,6 @@ public class InfluxStorageProvider extends ModuleProvider {
@Override
public String[] requiredModules() {
- return new String[]{CoreModule.NAME};
+ return new String[] {CoreModule.NAME};
}
}
diff --git a/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/query/BrowserLogQuery.java b/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/query/BrowserLogQuery.java
new file mode 100644
index 0000000..7d1fa1b
--- /dev/null
+++ b/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/query/BrowserLogQuery.java
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.storage.plugin.influxdb.query;
+
+import java.io.IOException;
+import java.util.List;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.apm.util.StringUtil;
+import org.apache.skywalking.oap.server.core.browser.manual.errorlog.BrowserErrorLogRecord;
+import org.apache.skywalking.oap.server.core.browser.source.BrowserErrorCategory;
+import org.apache.skywalking.oap.server.core.query.type.BrowserErrorLog;
+import org.apache.skywalking.oap.server.core.query.type.BrowserErrorLogs;
+import org.apache.skywalking.oap.server.core.storage.query.IBrowserLogQueryDAO;
+import org.apache.skywalking.oap.server.storage.plugin.influxdb.InfluxClient;
+import org.apache.skywalking.oap.server.storage.plugin.influxdb.InfluxConstants;
+import org.influxdb.dto.Query;
+import org.influxdb.dto.QueryResult;
+import org.influxdb.querybuilder.SelectQueryImpl;
+import org.influxdb.querybuilder.WhereQueryImpl;
+
+import static java.util.Objects.nonNull;
+import static org.influxdb.querybuilder.BuiltQuery.QueryBuilder.contains;
+import static org.influxdb.querybuilder.BuiltQuery.QueryBuilder.eq;
+import static org.influxdb.querybuilder.BuiltQuery.QueryBuilder.gte;
+import static org.influxdb.querybuilder.BuiltQuery.QueryBuilder.lte;
+import static org.influxdb.querybuilder.BuiltQuery.QueryBuilder.select;
+
+@Slf4j
+@RequiredArgsConstructor
+public class BrowserLogQuery implements IBrowserLogQueryDAO {
+ private final InfluxClient client;
+
+ @Override
+ public BrowserErrorLogs queryBrowserErrorLogs(final String serviceId,
+ final String serviceVersionId,
+ final String pagePathId,
+ final String pagePath,
+ final BrowserErrorCategory category,
+ final long startSecondTB,
+ final long endSecondTB,
+ final int limit,
+ final int from) throws IOException {
+
+ WhereQueryImpl<SelectQueryImpl> recallQuery = select()
+ .function(InfluxConstants.SORT_DES, BrowserErrorLogRecord.TIMESTAMP, limit + from)
+ .column(BrowserErrorLogRecord.DATA_BINARY)
+ .from(
+ client.getDatabase(),
+ BrowserErrorLogRecord.INDEX_NAME
+ ).where();
+ if (startSecondTB != 0 && endSecondTB != 0) {
+ recallQuery.and(gte(BrowserErrorLogRecord.TIME_BUCKET, startSecondTB))
+ .and(lte(BrowserErrorLogRecord.TIME_BUCKET, endSecondTB));
+ }
+ if (StringUtil.isNotEmpty(serviceId)) {
+ recallQuery.and(eq(BrowserErrorLogRecord.SERVICE_ID, serviceId));
+ }
+ if (StringUtil.isNotEmpty(serviceVersionId)) {
+ recallQuery.and(eq(BrowserErrorLogRecord.SERVICE_VERSION_ID, serviceVersionId));
+ }
+ if (StringUtil.isNotEmpty(pagePathId)) {
+ recallQuery.and(eq(BrowserErrorLogRecord.PAGE_PATH_ID, pagePathId));
+ }
+ if (nonNull(category)) {
+ recallQuery.and(eq(BrowserErrorLogRecord.ERROR_CATEGORY, category.getValue()));
+ }
+ if (StringUtil.isNotEmpty(pagePath)) {
+ recallQuery.and(contains(BrowserErrorLogRecord.PAGE_PATH, pagePath.replaceAll("/", "\\\\/")));
+ }
+
+ WhereQueryImpl<SelectQueryImpl> countQuery = select()
+ .count(BrowserErrorLogRecord.SERVICE_ID)
+ .from(client.getDatabase(), BrowserErrorLogRecord.INDEX_NAME)
+ .where();
+ recallQuery.getClauses().forEach(countQuery::where);
+
+ Query query = new Query(countQuery.getCommand() + recallQuery.getCommand());
+
+ List<QueryResult.Result> results = client.query(query);
+ if (log.isDebugEnabled()) {
+ log.debug("SQL: {} result set: {}", query.getCommand(), results);
+ }
+ if (results.size() != 2) {
+ throw new IOException("Expecting to get 2 Results, but it is " + results.size());
+ }
+
+ List<QueryResult.Series> counter = results.get(0).getSeries();
+ List<QueryResult.Series> result = results.get(1).getSeries();
+ if (result == null || result.isEmpty()) {
+ return new BrowserErrorLogs();
+ }
+
+ BrowserErrorLogs logs = new BrowserErrorLogs();
+ logs.setTotal(((Number) counter.get(0).getValues().get(0).get(1)).intValue());
+
+ result.get(0).getValues().stream().sorted((a, b) -> {
+ // Have to re-sort here. Because the function, top()/bottom(), get the result ordered by the `time`.
+ return Long.compare(((Number) b.get(1)).longValue(), ((Number) a.get(1)).longValue());
+ }).skip(from).forEach(values -> {
+ String dataBinaryBase64 = (String) values.get(2);
+ if (nonNull(dataBinaryBase64)) {
+ BrowserErrorLog log = parserDataBinary(dataBinaryBase64);
+ logs.getLogs().add(log);
+ }
+ });
+ return logs;
+ }
+}
diff --git a/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/query/MetadataQuery.java b/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/query/MetadataQuery.java
index 6b0d838..1ff91a1 100644
--- a/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/query/MetadataQuery.java
+++ b/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/query/MetadataQuery.java
@@ -83,7 +83,7 @@ public class MetadataQuery implements IMetadataQueryDAO {
public List<Service> getAllBrowserServices(long startTimestamp, long endTimestamp) throws IOException {
WhereQueryImpl<SelectQueryImpl> query = select(ID_COLUMN, NAME)
.from(client.getDatabase(), ServiceTraffic.INDEX_NAME)
- .where(eq(InfluxConstants.TagName.NODE_TYPE, String.valueOf(NodeType.Normal.value())));
+ .where(eq(InfluxConstants.TagName.NODE_TYPE, String.valueOf(NodeType.Browser.value())));
return buildServices(query);
}
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/H2StorageProvider.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/H2StorageProvider.java
index 82db553..b6f82ce 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/H2StorageProvider.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/H2StorageProvider.java
@@ -36,6 +36,7 @@ import org.apache.skywalking.oap.server.core.storage.profile.IProfileTaskQueryDA
import org.apache.skywalking.oap.server.core.storage.profile.IProfileThreadSnapshotQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IAggregationQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IAlarmQueryDAO;
+import org.apache.skywalking.oap.server.core.storage.query.IBrowserLogQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.ILogQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IMetadataQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IMetricsQueryDAO;
@@ -51,6 +52,7 @@ import org.apache.skywalking.oap.server.library.module.ServiceNotProvidedExcepti
import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2AggregationQueryDAO;
import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2AlarmQueryDAO;
import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2BatchDAO;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2BrowserLogQueryDAO;
import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2HistoryDeleteDAO;
import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2LogQueryDAO;
import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2MetadataQueryDAO;
@@ -129,6 +131,7 @@ public class H2StorageProvider extends ModuleProvider {
config.getMaxSizeOfArrayColumn(),
config.getNumOfSearchableValuesPerTag()
));
+ this.registerServiceImplementation(IBrowserLogQueryDAO.class, new H2BrowserLogQueryDAO(h2Client));
this.registerServiceImplementation(
IMetadataQueryDAO.class, new H2MetadataQueryDAO(h2Client, config.getMetadataQueryMaxSize()));
this.registerServiceImplementation(IAggregationQueryDAO.class, new H2AggregationQueryDAO(h2Client));
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2BrowserLogQueryDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2BrowserLogQueryDAO.java
new file mode 100644
index 0000000..909bf5e
--- /dev/null
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2BrowserLogQueryDAO.java
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao;
+
+import com.google.common.base.Strings;
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import lombok.RequiredArgsConstructor;
+import org.apache.skywalking.apm.util.StringUtil;
+import org.apache.skywalking.oap.server.core.browser.manual.errorlog.BrowserErrorLogRecord;
+import org.apache.skywalking.oap.server.core.browser.source.BrowserErrorCategory;
+import org.apache.skywalking.oap.server.core.query.type.BrowserErrorLog;
+import org.apache.skywalking.oap.server.core.query.type.BrowserErrorLogs;
+import org.apache.skywalking.oap.server.core.storage.query.IBrowserLogQueryDAO;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
+
+import static java.util.Objects.nonNull;
+
+@RequiredArgsConstructor
+public class H2BrowserLogQueryDAO implements IBrowserLogQueryDAO {
+ private final JDBCHikariCPClient h2Client;
+
+ @Override
+ public BrowserErrorLogs queryBrowserErrorLogs(String serviceId,
+ String serviceVersionId,
+ String pagePathId,
+ String pagePath,
+ BrowserErrorCategory category,
+ long startSecondTB,
+ long endSecondTB,
+ int limit,
+ int from) throws IOException {
+ StringBuilder sql = new StringBuilder();
+
+ List<Object> parameters = new ArrayList<>(9);
+
+ sql.append("from ").append(BrowserErrorLogRecord.INDEX_NAME)
+ .append(" where ").append(" 1=1 ");
+
+ if (startSecondTB != 0 && endSecondTB != 0) {
+ sql.append(" and ").append(BrowserErrorLogRecord.TIME_BUCKET).append(" >= ?");
+ parameters.add(startSecondTB);
+ sql.append(" and ").append(BrowserErrorLogRecord.TIME_BUCKET).append(" <= ?");
+ parameters.add(endSecondTB);
+ }
+
+ if (StringUtil.isNotEmpty(serviceId)) {
+ sql.append(" and ").append(BrowserErrorLogRecord.SERVICE_ID).append(" = ?");
+ parameters.add(serviceId);
+ }
+ if (StringUtil.isNotEmpty(serviceVersionId)) {
+ sql.append(" and ").append(BrowserErrorLogRecord.SERVICE_VERSION_ID).append(" = ?");
+ parameters.add(serviceVersionId);
+ }
+ if (StringUtil.isNotEmpty(pagePathId)) {
+ sql.append(" and ").append(BrowserErrorLogRecord.PAGE_PATH_ID).append(" = ?");
+ parameters.add(pagePathId);
+ }
+ if (nonNull(category)) {
+ sql.append(" and ").append(BrowserErrorLogRecord.ERROR_CATEGORY).append(" = ?");
+ parameters.add(category.getValue());
+ }
+ if (!Strings.isNullOrEmpty(pagePath)) {
+ sql.append(" and ").append(BrowserErrorLogRecord.PAGE_PATH).append(" like concat('%',?,'%')");
+ parameters.add(pagePath);
+ }
+
+ BrowserErrorLogs logs = new BrowserErrorLogs();
+ try (Connection connection = h2Client.getConnection()) {
+
+ try (ResultSet resultSet = h2Client.executeQuery(connection, buildCountStatement(sql.toString()), parameters
+ .toArray(new Object[0]))) {
+ while (resultSet.next()) {
+ logs.setTotal(resultSet.getInt("total"));
+ }
+ }
+
+ buildLimit(sql, from, limit);
+
+ try (ResultSet resultSet = h2Client.executeQuery(
+ connection, "select " + BrowserErrorLogRecord.DATA_BINARY + " " + sql.toString(),
+ parameters.toArray(new Object[0])
+ )) {
+ while (resultSet.next()) {
+ String dataBinaryBase64 = resultSet.getString(BrowserErrorLogRecord.DATA_BINARY);
+ if (nonNull(dataBinaryBase64)) {
+ BrowserErrorLog log = parserDataBinary(dataBinaryBase64);
+ logs.getLogs().add(log);
+ }
+ }
+ }
+ } catch (SQLException e) {
+ throw new IOException(e);
+ }
+ return logs;
+ }
+
+ protected String buildCountStatement(String sql) {
+ return "select count(1) total from (select 1 " + sql + " )";
+ }
+
+ protected void buildLimit(StringBuilder sql, int from, int limit) {
+ sql.append(" limit ").append(limit);
+ sql.append(" offset ").append(from);
+ }
+}
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/mysql/MySQLStorageProvider.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/mysql/MySQLStorageProvider.java
index 765c252..6c3f502 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/mysql/MySQLStorageProvider.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/mysql/MySQLStorageProvider.java
@@ -35,6 +35,7 @@ import org.apache.skywalking.oap.server.core.storage.profile.IProfileTaskQueryDA
import org.apache.skywalking.oap.server.core.storage.profile.IProfileThreadSnapshotQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IAggregationQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IAlarmQueryDAO;
+import org.apache.skywalking.oap.server.core.storage.query.IBrowserLogQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.ILogQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IMetadataQueryDAO;
import org.apache.skywalking.oap.server.core.storage.query.IMetricsQueryDAO;
@@ -117,6 +118,7 @@ public class MySQLStorageProvider extends ModuleProvider {
config.getNumOfSearchableValuesPerTag()
)
);
+ this.registerServiceImplementation(IBrowserLogQueryDAO.class, new MysqlBrowserLogQueryDAO(mysqlClient));
this.registerServiceImplementation(
IMetadataQueryDAO.class, new H2MetadataQueryDAO(mysqlClient, config.getMetadataQueryMaxSize()));
this.registerServiceImplementation(IAggregationQueryDAO.class, new MySQLAggregationQueryDAO(mysqlClient));
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/expression/InMatch.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/mysql/MysqlBrowserLogQueryDAO.java
similarity index 53%
copy from oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/expression/InMatch.java
copy to oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/mysql/MysqlBrowserLogQueryDAO.java
index 2873f3d..b710a9c 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/expression/InMatch.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/mysql/MysqlBrowserLogQueryDAO.java
@@ -15,26 +15,23 @@
* limitations under the License.
*/
-package org.apache.skywalking.oap.server.core.analysis.metrics.expression;
+package org.apache.skywalking.oap.server.storage.plugin.jdbc.mysql;
-import java.util.Objects;
-import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.FilterMatcher;
+import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
+import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2BrowserLogQueryDAO;
-@FilterMatcher
-public class InMatch {
+public class MysqlBrowserLogQueryDAO extends H2BrowserLogQueryDAO {
+ public MysqlBrowserLogQueryDAO(final JDBCHikariCPClient h2Client) {
+ super(h2Client);
+ }
+
+ @Override
+ protected String buildCountStatement(String sql) {
+ return "select count(1) total " + sql;
+ }
- public boolean match(Object left, Object[] rights) {
- for (Object right : rights) {
- if (right instanceof String) {
- String r = (String) right;
- if (r.startsWith("\"") && r.endsWith("\"")) {
- right = r.substring(1, r.length() - 1);
- }
- }
- if (Objects.equals(left, right)) {
- return true;
- }
- }
- return false;
+ @Override
+ protected void buildLimit(StringBuilder sql, int from, int limit) {
+ sql.append(" limit ").append(from).append(", ").append(limit);
}
}
diff --git a/oap-server/server-tools/profile-exporter/tool-profile-snapshot-server-mock/src/main/java/org/apache/skywalking/oap/server/tool/profile/core/MockCoreModuleProvider.java b/oap-server/server-tools/profile-exporter/tool-profile-snapshot-server-mock/src/main/java/org/apache/skywalking/oap/server/tool/profile/core/MockCoreModuleProvider.java
index 71f1d9a..abd9839 100755
--- a/oap-server/server-tools/profile-exporter/tool-profile-snapshot-server-mock/src/main/java/org/apache/skywalking/oap/server/tool/profile/core/MockCoreModuleProvider.java
+++ b/oap-server/server-tools/profile-exporter/tool-profile-snapshot-server-mock/src/main/java/org/apache/skywalking/oap/server/tool/profile/core/MockCoreModuleProvider.java
@@ -38,6 +38,7 @@ import org.apache.skywalking.oap.server.core.oal.rt.OALEngineLoaderService;
import org.apache.skywalking.oap.server.core.profile.ProfileTaskMutationService;
import org.apache.skywalking.oap.server.core.query.AggregationQueryService;
import org.apache.skywalking.oap.server.core.query.AlarmQueryService;
+import org.apache.skywalking.oap.server.core.query.BrowserLogQueryService;
import org.apache.skywalking.oap.server.core.query.LogQueryService;
import org.apache.skywalking.oap.server.core.query.MetadataQueryService;
import org.apache.skywalking.oap.server.core.query.MetricsMetadataQueryService;
@@ -146,6 +147,7 @@ public class MockCoreModuleProvider extends CoreModuleProvider {
this.registerServiceImplementation(MetricsMetadataQueryService.class, new MetricsMetadataQueryService());
this.registerServiceImplementation(MetricsQueryService.class, new MetricsQueryService(getManager()));
this.registerServiceImplementation(TraceQueryService.class, new TraceQueryService(getManager()));
+ this.registerServiceImplementation(BrowserLogQueryService.class, new BrowserLogQueryService(getManager()));
this.registerServiceImplementation(LogQueryService.class, new LogQueryService(getManager()));
this.registerServiceImplementation(MetadataQueryService.class, new MetadataQueryService(getManager()));
this.registerServiceImplementation(AggregationQueryService.class, new AggregationQueryService(getManager()));
diff --git a/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/SimpleQueryClient.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/SimpleQueryClient.java
index 5287dc3..f2ef797 100644
--- a/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/SimpleQueryClient.java
+++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/SimpleQueryClient.java
@@ -25,14 +25,18 @@ import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.e2e.browser.BrowserErrorLog;
+import org.apache.skywalking.e2e.browser.BrowserErrorLogQuery;
+import org.apache.skywalking.e2e.browser.BrowserErrorLogsData;
import org.apache.skywalking.e2e.metrics.Metrics;
import org.apache.skywalking.e2e.metrics.MetricsData;
import org.apache.skywalking.e2e.metrics.MetricsQuery;
import org.apache.skywalking.e2e.metrics.MultiMetricsData;
import org.apache.skywalking.e2e.metrics.ReadLabeledMetricsData;
-import org.apache.skywalking.e2e.metrics.ReadMetricsQuery;
import org.apache.skywalking.e2e.metrics.ReadMetrics;
import org.apache.skywalking.e2e.metrics.ReadMetricsData;
+import org.apache.skywalking.e2e.metrics.ReadMetricsQuery;
import org.apache.skywalking.e2e.service.Service;
import org.apache.skywalking.e2e.service.ServicesData;
import org.apache.skywalking.e2e.service.ServicesQuery;
@@ -43,8 +47,8 @@ import org.apache.skywalking.e2e.service.instance.InstancesQuery;
import org.apache.skywalking.e2e.topo.ServiceInstanceTopology;
import org.apache.skywalking.e2e.topo.ServiceInstanceTopologyQuery;
import org.apache.skywalking.e2e.topo.ServiceInstanceTopologyResponse;
-import org.apache.skywalking.e2e.topo.Topology;
import org.apache.skywalking.e2e.topo.TopoQuery;
+import org.apache.skywalking.e2e.topo.Topology;
import org.apache.skywalking.e2e.topo.TopologyResponse;
import org.apache.skywalking.e2e.trace.Trace;
import org.apache.skywalking.e2e.trace.TracesData;
@@ -56,8 +60,6 @@ import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
-import lombok.extern.slf4j.Slf4j;
-
@SuppressWarnings("UnstableApiUsage")
@Slf4j
public class SimpleQueryClient {
@@ -100,8 +102,41 @@ public class SimpleQueryClient {
return Objects.requireNonNull(responseEntity.getBody()).getData().getTraces().getData();
}
+ public List<BrowserErrorLog> browserErrorLogs(final BrowserErrorLogQuery query) throws Exception {
+ final URL queryFileUrl = Resources.getResource("browser-error-logs.gql");
+ final String queryString = Resources.readLines(queryFileUrl, StandardCharsets.UTF_8)
+ .stream()
+ .filter(it -> !it.startsWith("#"))
+ .collect(Collectors.joining())
+ .replace("{start}", query.start())
+ .replace("{end}", query.end())
+ .replace("{step}", query.step())
+ .replace("{pageNum}", query.pageNum())
+ .replace("{pageSize}", query.pageSize())
+ .replace("{needTotal}", query.needTotal());
+ final ResponseEntity<GQLResponse<BrowserErrorLogsData>> responseEntity = restTemplate.exchange(
+ new RequestEntity<>(queryString, HttpMethod.POST, URI.create(endpointUrl)),
+ new ParameterizedTypeReference<GQLResponse<BrowserErrorLogsData>>() {
+ }
+ );
+
+ if (responseEntity.getStatusCode() != HttpStatus.OK) {
+ throw new RuntimeException("Response status != 200, actual: " + responseEntity.getStatusCode());
+ }
+
+ return Objects.requireNonNull(responseEntity.getBody().getData().getLogs().getData());
+ }
+
public List<Service> services(final ServicesQuery query) throws Exception {
- final URL queryFileUrl = Resources.getResource("services.gql");
+ return services(query, "services.gql");
+ }
+
+ public List<Service> browserServices(final ServicesQuery query) throws Exception {
+ return services(query, "browser-services.gql");
+ }
+
+ private List<Service> services(final ServicesQuery query, String gql) throws Exception {
+ final URL queryFileUrl = Resources.getResource(gql);
final String queryString = Resources.readLines(queryFileUrl, StandardCharsets.UTF_8)
.stream()
.filter(it -> !it.startsWith("#"))
diff --git a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/browser/BrowserErrorLog.java
similarity index 57%
copy from test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java
copy to test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/browser/BrowserErrorLog.java
index 6c35a88..fea3b50 100644
--- a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java
+++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/browser/BrowserErrorLog.java
@@ -6,23 +6,33 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* 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.
- *
*/
-package org.apache.skywalking.e2e.utils;
+package org.apache.skywalking.e2e.browser;
-import java.time.LocalDateTime;
-import java.time.ZoneOffset;
+import lombok.Data;
+import lombok.experimental.Accessors;
-public final class Times {
- public static LocalDateTime now() {
- return LocalDateTime.now(ZoneOffset.UTC);
- }
+@Data
+@Accessors(chain = true)
+public class BrowserErrorLog {
+ private String service;
+ private String serviceVersion;
+ private Long time;
+ private String pagePath;
+ private String category;
+ private String grade;
+ private String message;
+ private Integer line;
+ private Integer col;
+ private String stack;
+ private String errorUrl;
+ private boolean firstReportedError;
}
diff --git a/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/browser/BrowserErrorLogMatcher.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/browser/BrowserErrorLogMatcher.java
new file mode 100644
index 0000000..1ac9547
--- /dev/null
+++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/browser/BrowserErrorLogMatcher.java
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.e2e.browser;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.apache.skywalking.e2e.verification.AbstractMatcher;
+
+import static java.util.Objects.nonNull;
+
+@Data
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+public class BrowserErrorLogMatcher extends AbstractMatcher<BrowserErrorLog> {
+ private String service;
+ private String serviceVersion;
+ private String time;
+ private String pagePath;
+ private String category;
+ private String grade;
+ private String message;
+ private String line;
+ private String col;
+ private String stack;
+ private String errorUrl;
+ private String firstReportedError;
+
+ @Override
+ public void verify(final BrowserErrorLog log) {
+ if (nonNull(getService())) {
+ doVerify(getService(), log.getService());
+ }
+
+ if (nonNull(getServiceVersion())) {
+ doVerify(getServiceVersion(), log.getServiceVersion());
+ }
+
+ if (nonNull(getTime())) {
+ doVerify(getTime(), String.valueOf(log.getTime()));
+ }
+
+ if (nonNull(getPagePath())) {
+ doVerify(getPagePath(), log.getPagePath());
+ }
+
+ if (nonNull(getCategory())) {
+ doVerify(getCategory(), log.getCategory());
+ }
+
+ if (nonNull(getGrade())) {
+ doVerify(getGrade(), log.getGrade());
+ }
+
+ if (nonNull(getMessage())) {
+ doVerify(getMessage(), log.getMessage());
+ }
+
+ if (nonNull(getLine())) {
+ doVerify(getLine(), String.valueOf(log.getLine()));
+ }
+
+ if (nonNull(getCol())) {
+ doVerify(getCol(), String.valueOf(log.getCol()));
+ }
+
+ if (nonNull(getStack())) {
+ doVerify(getStack(), log.getStack());
+ }
+
+ if (nonNull(getErrorUrl())) {
+ doVerify(getErrorUrl(), log.getErrorUrl());
+ }
+
+ if (nonNull(getFirstReportedError())) {
+ doVerify(getFirstReportedError(), String.valueOf(log.isFirstReportedError()));
+ }
+ }
+}
diff --git a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/browser/BrowserErrorLogQuery.java
similarity index 54%
copy from oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
copy to test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/browser/BrowserErrorLogQuery.java
index ba3facc..4cdfda2 100644
--- a/oap-server/server-core/src/test/java/org/apache/skywalking/oap/server/core/CoreModuleTest.java
+++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/browser/BrowserErrorLogQuery.java
@@ -6,26 +6,39 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* 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.
- *
*/
-package org.apache.skywalking.oap.server.core;
+package org.apache.skywalking.e2e.browser;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import org.apache.skywalking.e2e.AbstractQuery;
-import org.junit.Assert;
-import org.junit.Test;
+@Setter
+@Getter
+@Accessors(chain = true)
+public class BrowserErrorLogQuery extends AbstractQuery<BrowserErrorLogQuery> {
+ private String pageNum = "1";
+ private String pageSize = "15";
+ private String needTotal = "true";
-public class CoreModuleTest {
- @Test
- public void testOpenServiceList() {
- CoreModule coreModule = new CoreModule();
+ public String pageNum() {
+ return pageNum;
+ }
+
+ public String pageSize() {
+ return pageSize;
+ }
- Assert.assertEquals(31, coreModule.services().length);
+ public String needTotal() {
+ return needTotal;
}
}
diff --git a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/browser/BrowserErrorLogs.java
similarity index 73%
copy from test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java
copy to test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/browser/BrowserErrorLogs.java
index 6c35a88..4997e76 100644
--- a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java
+++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/browser/BrowserErrorLogs.java
@@ -6,23 +6,21 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* 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.
- *
*/
-package org.apache.skywalking.e2e.utils;
+package org.apache.skywalking.e2e.browser;
-import java.time.LocalDateTime;
-import java.time.ZoneOffset;
+import java.util.List;
+import lombok.Data;
-public final class Times {
- public static LocalDateTime now() {
- return LocalDateTime.now(ZoneOffset.UTC);
- }
+@Data
+public class BrowserErrorLogs {
+ private List<BrowserErrorLog> data;
}
diff --git a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/browser/BrowserErrorLogsData.java
similarity index 73%
copy from test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java
copy to test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/browser/BrowserErrorLogsData.java
index 6c35a88..d21d0ff 100644
--- a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java
+++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/browser/BrowserErrorLogsData.java
@@ -6,23 +6,20 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* 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.
- *
*/
-package org.apache.skywalking.e2e.utils;
+package org.apache.skywalking.e2e.browser;
-import java.time.LocalDateTime;
-import java.time.ZoneOffset;
+import lombok.Data;
-public final class Times {
- public static LocalDateTime now() {
- return LocalDateTime.now(ZoneOffset.UTC);
- }
+@Data
+public class BrowserErrorLogsData {
+ private BrowserErrorLogs logs;
}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/expression/InMatch.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/browser/BrowserErrorLogsMatcher.java
similarity index 51%
copy from oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/expression/InMatch.java
copy to test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/browser/BrowserErrorLogsMatcher.java
index 2873f3d..c3871ed 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/metrics/expression/InMatch.java
+++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/browser/BrowserErrorLogsMatcher.java
@@ -15,26 +15,36 @@
* limitations under the License.
*/
-package org.apache.skywalking.oap.server.core.analysis.metrics.expression;
+package org.apache.skywalking.e2e.browser;
-import java.util.Objects;
-import org.apache.skywalking.oap.server.core.analysis.metrics.annotation.FilterMatcher;
+import java.util.LinkedList;
+import java.util.List;
+import lombok.Data;
-@FilterMatcher
-public class InMatch {
+import static org.assertj.core.api.Assertions.fail;
+
+@Data
+public class BrowserErrorLogsMatcher {
+ private List<BrowserErrorLogMatcher> logs;
+
+ public BrowserErrorLogsMatcher() {
+ this.logs = new LinkedList<>();
+ }
+
+ public void verifyLoosely(final List<BrowserErrorLog> logs) {
+ for (final BrowserErrorLogMatcher matcher : getLogs()) {
+ boolean matched = false;
+ for (final BrowserErrorLog log : logs) {
+ try {
+ matcher.verify(log);
+ matched = true;
+ } catch (Throwable throwable) {
- public boolean match(Object left, Object[] rights) {
- for (Object right : rights) {
- if (right instanceof String) {
- String r = (String) right;
- if (r.startsWith("\"") && r.endsWith("\"")) {
- right = r.substring(1, r.length() - 1);
}
}
- if (Objects.equals(left, right)) {
- return true;
+ if (!matched) {
+ fail("\nExpected: %s\n Actual: %s", getLogs(), logs);
}
}
- return false;
}
}
diff --git a/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/metrics/BrowserMetricsQuery.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/metrics/BrowserMetricsQuery.java
new file mode 100644
index 0000000..a8c910e
--- /dev/null
+++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/metrics/BrowserMetricsQuery.java
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.e2e.metrics;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.apache.skywalking.e2e.AbstractQuery;
+
+@Data
+@Accessors(fluent = true)
+@EqualsAndHashCode(callSuper = true)
+public class BrowserMetricsQuery extends AbstractQuery<BrowserMetricsQuery> {
+ public static final String BROWSER_APP_PV = "browser_app_pv";
+ public static final String BROWSER_APP_ERROR_RATE = "browser_app_error_rate";
+ public static final String BROWSER_APP_ERROR_SUM = "browser_app_error_sum";
+
+ public static final String[] ALL_BROWSER_METRICS = {
+ BROWSER_APP_PV,
+ BROWSER_APP_ERROR_SUM,
+ BROWSER_APP_ERROR_RATE
+ };
+
+ public static final String BROWSER_APP_SINGLE_VERSION_PV = "browser_app_single_version_pv";
+ public static final String BROWSER_APP_SINGLE_VERSION_ERROR_RATE = "browser_app_single_version_error_rate";
+ public static final String BROWSER_APP_SINGLE_VERSION_ERROR_SUM = "browser_app_single_version_error_sum";
+
+ public static final String[] ALL_BROWSER_SINGLE_VERSION_METRICS = {
+ BROWSER_APP_SINGLE_VERSION_PV,
+ BROWSER_APP_SINGLE_VERSION_ERROR_RATE,
+ BROWSER_APP_SINGLE_VERSION_ERROR_SUM
+ };
+
+ public static final String BROWSER_APP_PAGE_PV = "browser_app_page_pv";
+ public static final String BROWSER_APP_PAGE_ERROR_RATE = "browser_app_page_error_rate";
+ public static final String BROWSER_APP_PAGE_ERROR_SUM = "browser_app_page_error_sum";
+
+ public static final String BROWSER_APP_PAGE_AJAX_ERROR_SUM = "browser_app_page_ajax_error_sum";
+ public static final String BROWSER_APP_PAGE_RESOURCE_ERROR_SUM = "browser_app_page_resource_error_sum";
+ public static final String BROWSER_APP_PAGE_JS_ERROR_SUM = "browser_app_page_js_error_sum";
+ public static final String BROWSER_APP_PAGE_UNKNOWN_ERROR_SUM = "browser_app_page_unknown_error_sum";
+
+ public static final String BROWSER_APP_PAGE_REDIRECT_AVG = "browser_app_page_redirect_avg";
+ public static final String BROWSER_APP_PAGE_DNS_AVG = "browser_app_page_dns_avg";
+ public static final String BROWSER_APP_PAGE_TTFB_AVG = "browser_app_page_ttfb_avg";
+ public static final String BROWSER_APP_PAGE_TCP_AVG = "browser_app_page_tcp_avg";
+ public static final String BROWSER_APP_PAGE_TRANS_AVG = "browser_app_page_trans_avg";
+ public static final String BROWSER_APP_PAGE_DOM_ANALYSIS_AVG = "browser_app_page_dom_analysis_avg";
+ public static final String BROWSER_APP_PAGE_FPT_AVG = "browser_app_page_fpt_avg";
+ public static final String BROWSER_APP_PAGE_DOM_READY_AVG = "browser_app_page_dom_ready_avg";
+ public static final String BROWSER_APP_PAGE_LOAD_PAGE_AVG = "browser_app_page_load_page_avg";
+ public static final String BROWSER_APP_PAGE_RES_AVG = "browser_app_page_res_avg";
+ public static final String BROWSER_APP_PAGE_SSL_AVG = "browser_app_page_ssl_avg";
+ public static final String BROWSER_APP_PAGE_TTL_AVG = "browser_app_page_ttl_avg";
+ public static final String BROWSER_APP_PAGE_FIRST_PACK_AVG = "browser_app_page_first_pack_avg";
+ public static final String BROWSER_APP_PAGE_FMP_AVG = "browser_app_page_fmp_avg";
+
+ public static final String[] ALL_BROWSER_PAGE_METRICS = {
+ BROWSER_APP_PAGE_PV,
+ BROWSER_APP_PAGE_ERROR_RATE,
+ BROWSER_APP_PAGE_ERROR_SUM,
+ BROWSER_APP_PAGE_AJAX_ERROR_SUM,
+ BROWSER_APP_PAGE_RESOURCE_ERROR_SUM,
+ BROWSER_APP_PAGE_JS_ERROR_SUM,
+ BROWSER_APP_PAGE_UNKNOWN_ERROR_SUM,
+ BROWSER_APP_PAGE_REDIRECT_AVG,
+ BROWSER_APP_PAGE_DNS_AVG,
+ BROWSER_APP_PAGE_TTFB_AVG,
+ BROWSER_APP_PAGE_TCP_AVG,
+ BROWSER_APP_PAGE_TRANS_AVG,
+ BROWSER_APP_PAGE_DOM_ANALYSIS_AVG,
+ BROWSER_APP_PAGE_FPT_AVG,
+ BROWSER_APP_PAGE_DOM_READY_AVG,
+ BROWSER_APP_PAGE_LOAD_PAGE_AVG,
+ BROWSER_APP_PAGE_RES_AVG,
+ BROWSER_APP_PAGE_SSL_AVG,
+ BROWSER_APP_PAGE_TTL_AVG,
+ BROWSER_APP_PAGE_FIRST_PACK_AVG,
+ BROWSER_APP_PAGE_FMP_AVG
+ };
+
+ public static final String BROWSER_APP_PAGE_FPT_PERCENTILE = "browser_app_page_fpt_percentile";
+ public static final String BROWSER_APP_PAGE_DOM_READY_PERCENTILE = "browser_app_page_dom_ready_percentile";
+ public static final String BROWSER_APP_PAGE_LOAD_PAGE_PERCENTILE = "browser_app_page_load_page_percentile";
+ public static final String BROWSER_APP_PAGE_TTL_PERCENTILE = "browser_app_page_ttl_percentile";
+ public static final String BROWSER_APP_PAGE_FIRST_PACK_PERCENTILE = "browser_app_page_first_pack_percentile";
+ public static final String BROWSER_APP_PAGE_FMP_PERCENTILE = "browser_app_page_fmp_percentile";
+
+ public static final String[] ALL_BROWSER_PAGE_MULTIPLE_LINEAR_METRICS = {
+ BROWSER_APP_PAGE_FPT_PERCENTILE,
+ BROWSER_APP_PAGE_TTL_PERCENTILE,
+ BROWSER_APP_PAGE_DOM_READY_PERCENTILE,
+ BROWSER_APP_PAGE_LOAD_PAGE_PERCENTILE,
+ BROWSER_APP_PAGE_FIRST_PACK_PERCENTILE,
+ BROWSER_APP_PAGE_FMP_PERCENTILE
+ };
+}
diff --git a/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/metrics/MetricsMatcher.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/metrics/MetricsMatcher.java
index fdb8ac5..0ae938c 100644
--- a/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/metrics/MetricsMatcher.java
+++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/metrics/MetricsMatcher.java
@@ -19,10 +19,10 @@
package org.apache.skywalking.e2e.metrics;
import java.time.LocalDateTime;
-import java.time.ZoneOffset;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.apache.skywalking.e2e.SimpleQueryClient;
+import org.apache.skywalking.e2e.utils.Times;
@Slf4j
public class MetricsMatcher {
@@ -46,7 +46,7 @@ public class MetricsMatcher {
new MetricsQuery().stepByMinute()
.metricsName(metricName)
.start(minutesAgo)
- .end(LocalDateTime.now(ZoneOffset.UTC).plusMinutes(1))
+ .end(Times.now().plusMinutes(1))
.id(id));
LOGGER.info("{}: {}", metricName, metrics);
AtLeastOneOfMetricsMatcher instanceRespTimeMatcher = new AtLeastOneOfMetricsMatcher();
@@ -70,6 +70,13 @@ public class MetricsMatcher {
public static void verifyPercentileMetrics(final SimpleQueryClient queryClient,
final String metricName,
final String id,
+ final LocalDateTime minutesAgo) throws Exception {
+ verifyPercentileMetrics(queryClient, metricName, id, minutesAgo, 0, null);
+ }
+
+ public static void verifyPercentileMetrics(final SimpleQueryClient queryClient,
+ final String metricName,
+ final String id,
final LocalDateTime minutesAgo,
final long retryInterval,
final Runnable generateTraffic) throws Exception {
@@ -79,7 +86,7 @@ public class MetricsMatcher {
new MetricsQuery().stepByMinute()
.metricsName(metricName)
.start(minutesAgo)
- .end(LocalDateTime.now(ZoneOffset.UTC).plusMinutes(1))
+ .end(Times.now().plusMinutes(1))
.id(id), "5");
LOGGER.info("{}: {}", metricName, metricsArray);
AtLeastOneOfMetricsMatcher matcher = new AtLeastOneOfMetricsMatcher();
diff --git a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/utils/Times.java
similarity index 94%
rename from test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java
rename to test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/utils/Times.java
index 6c35a88..71b9221 100644
--- a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/utils/Times.java
+++ b/test/e2e/e2e-data/src/main/java/org/apache/skywalking/e2e/utils/Times.java
@@ -6,14 +6,13 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* 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.
- *
*/
package org.apache.skywalking.e2e.utils;
diff --git a/test/e2e/e2e-data/src/main/resources/browser-error-logs.gql b/test/e2e/e2e-data/src/main/resources/browser-error-logs.gql
new file mode 100644
index 0000000..912eeb7
--- /dev/null
+++ b/test/e2e/e2e-data/src/main/resources/browser-error-logs.gql
@@ -0,0 +1,39 @@
+# 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.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# 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.
+
+{
+ "query": "query queryBrowserLog($condition: BrowserErrorLogQueryCondition) {
+ logs: queryBrowserErrorLogs(condition: $condition) {
+ data: logs {
+ service serviceVersion time pagePath category grade, message, line, col, stack, errorUrl, firstReportedError
+ }
+ total
+ }
+ }",
+ "variables": {
+ "condition": {
+ "queryDuration": {
+ "start": "{start}",
+ "end": "{end}",
+ "step": "{step}"
+ },
+ "paging": {
+ "pageNum": {pageNum},
+ "pageSize": {pageSize},
+ "needTotal": {needTotal}
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/e2e/e2e-data/src/main/resources/browser-services.gql b/test/e2e/e2e-data/src/main/resources/browser-services.gql
new file mode 100644
index 0000000..5257d64
--- /dev/null
+++ b/test/e2e/e2e-data/src/main/resources/browser-services.gql
@@ -0,0 +1,31 @@
+# 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. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# 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.
+
+{
+ "query": "query queryServices($duration: Duration!) {
+ services: getAllBrowserServices(duration: $duration) {
+ key: id
+ label: name
+ }
+ }",
+ "variables": {
+ "duration": {
+ "start": "{start}",
+ "end": "{end}",
+ "step": "{step}"
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/e2e/e2e-protocol/src/main/proto b/test/e2e/e2e-protocol/src/main/proto
index 7e56389..b2f381e 160000
--- a/test/e2e/e2e-protocol/src/main/proto
+++ b/test/e2e/e2e-protocol/src/main/proto
@@ -1 +1 @@
-Subproject commit 7e563891f3cfaf5c19ad086434af93aaab996719
+Subproject commit b2f381e63702bc43216ef5576637195102302c6e
diff --git a/test/e2e/e2e-test/docker/browser/Dockerfile.h2 b/test/e2e/e2e-test/docker/browser/Dockerfile.h2
new file mode 100644
index 0000000..b77f407
--- /dev/null
+++ b/test/e2e/e2e-test/docker/browser/Dockerfile.h2
@@ -0,0 +1,24 @@
+# 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.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# 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.
+
+FROM adoptopenjdk/openjdk8:alpine
+
+WORKDIR /h2
+
+VOLUME /h2/data
+
+ADD https://repo.maven.apache.org/maven2/com/h2database/h2/1.4.200/h2-1.4.200.jar /h2
+
+CMD ["sh", "-c", "java -cp /h2/*.jar org.h2.tools.Server -tcp -tcpAllowOthers -tcpPort 1521 -ifNotExists -baseDir /h2/data"]
\ No newline at end of file
diff --git a/test/e2e/e2e-test/docker/browser/docker-compose.es6.yml b/test/e2e/e2e-test/docker/browser/docker-compose.es6.yml
new file mode 100644
index 0000000..beefbff
--- /dev/null
+++ b/test/e2e/e2e-test/docker/browser/docker-compose.es6.yml
@@ -0,0 +1,44 @@
+# 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.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# 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.
+
+version: '2.1'
+
+services:
+ es:
+ image: elastic/elasticsearch:6.3.2
+ expose:
+ - 9200
+ networks:
+ - e2e
+ environment:
+ - discovery.type=single-node
+ healthcheck:
+ test: ["CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/9200"]
+ interval: 5s
+ timeout: 60s
+ retries: 120
+
+ oap:
+ extends:
+ file: ../base-compose.yml
+ service: oap
+ environment:
+ SW_STORAGE: elasticsearch
+ depends_on:
+ es:
+ condition: service_healthy
+
+networks:
+ e2e:
\ No newline at end of file
diff --git a/test/e2e/e2e-test/docker/browser/docker-compose.es7.yml b/test/e2e/e2e-test/docker/browser/docker-compose.es7.yml
new file mode 100644
index 0000000..28c79a7
--- /dev/null
+++ b/test/e2e/e2e-test/docker/browser/docker-compose.es7.yml
@@ -0,0 +1,44 @@
+# 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.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# 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.
+
+version: '2.1'
+
+services:
+ es:
+ image: elastic/elasticsearch:7.4.2
+ expose:
+ - 9200
+ networks:
+ - e2e
+ environment:
+ - discovery.type=single-node
+ healthcheck:
+ test: ["CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/9200"]
+ interval: 5s
+ timeout: 60s
+ retries: 120
+
+ oap:
+ extends:
+ file: ../base-compose.yml
+ service: oap-es7
+ environment:
+ SW_STORAGE: elasticsearch7
+ depends_on:
+ es:
+ condition: service_healthy
+
+networks:
+ e2e:
\ No newline at end of file
diff --git a/test/e2e/e2e-test/docker/browser/docker-compose.h2.yml b/test/e2e/e2e-test/docker/browser/docker-compose.h2.yml
new file mode 100644
index 0000000..1c2b536
--- /dev/null
+++ b/test/e2e/e2e-test/docker/browser/docker-compose.h2.yml
@@ -0,0 +1,45 @@
+# 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.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# 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.
+
+version: '2.1'
+
+services:
+ h2db:
+ build:
+ context: .
+ dockerfile: Dockerfile.h2
+ networks:
+ - e2e
+ expose:
+ - 1521
+ healthcheck:
+ test: ["CMD", "sh", "-c", "nc -z 127.0.0.1 1521"]
+ interval: 5s
+ timeout: 60s
+ retries: 120
+
+ oap:
+ extends:
+ file: ../base-compose.yml
+ service: oap
+ environment:
+ SW_STORAGE: h2
+ SW_STORAGE_H2_URL: jdbc:h2:tcp://h2db:1521/skywalking-oap-db
+ depends_on:
+ h2db:
+ condition: service_healthy
+
+networks:
+ e2e:
\ No newline at end of file
diff --git a/test/e2e/e2e-test/docker/browser/docker-compose.influxdb.yml b/test/e2e/e2e-test/docker/browser/docker-compose.influxdb.yml
new file mode 100644
index 0000000..6313f35
--- /dev/null
+++ b/test/e2e/e2e-test/docker/browser/docker-compose.influxdb.yml
@@ -0,0 +1,42 @@
+# 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.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# 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.
+
+version: '2.1'
+
+services:
+ influxdb:
+ image: influxdb:1.7.9
+ expose:
+ - 8086
+ networks:
+ - e2e
+ healthcheck:
+ test: ["CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/8086"]
+ interval: 5s
+ timeout: 60s
+ retries: 120
+
+ oap:
+ extends:
+ file: ../base-compose.yml
+ service: oap
+ environment:
+ SW_STORAGE: influxdb
+ depends_on:
+ influxdb:
+ condition: service_healthy
+
+networks:
+ e2e:
\ No newline at end of file
diff --git a/test/e2e/e2e-test/docker/browser/docker-compose.mysql.yml b/test/e2e/e2e-test/docker/browser/docker-compose.mysql.yml
new file mode 100644
index 0000000..d577079
--- /dev/null
+++ b/test/e2e/e2e-test/docker/browser/docker-compose.mysql.yml
@@ -0,0 +1,47 @@
+# 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.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# 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.
+
+version: '2.1'
+
+services:
+ mysql:
+ image: mysql/mysql-server:8.0.13
+ networks:
+ - e2e
+ expose:
+ - 3306
+ environment:
+ - MYSQL_ROOT_PASSWORD=root@1234
+ - MYSQL_DATABASE=swtest
+ - MYSQL_ROOT_HOST=%
+ healthcheck:
+ test: ["CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/3306"]
+ interval: 5s
+ timeout: 60s
+ retries: 120
+
+ oap:
+ extends:
+ file: ../base-compose.yml
+ service: oap
+ environment:
+ SW_STORAGE: mysql
+ depends_on:
+ mysql:
+ condition: service_healthy
+ entrypoint: ['sh', '-c', '/download-mysql.sh && /skywalking/docker-entrypoint.sh']
+
+networks:
+ e2e:
\ No newline at end of file
diff --git a/test/e2e/e2e-test/docker/browser/download-mysql.sh b/test/e2e/e2e-test/docker/browser/download-mysql.sh
new file mode 100644
index 0000000..f93caa4
--- /dev/null
+++ b/test/e2e/e2e-test/docker/browser/download-mysql.sh
@@ -0,0 +1,26 @@
+# 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.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# 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.
+
+set -ex
+
+SW_HOME=/skywalking
+MYSQL_URL="https://repo.maven.apache.org/maven2/mysql/mysql-connector-java/8.0.13/mysql-connector-java-8.0.13.jar"
+MYSQL_DRIVER="mysql-connector-java-8.0.13.jar"
+
+curl -L -o "${SW_HOME}/oap-libs/${MYSQL_DRIVER}" ${MYSQL_URL}
+if [[ $? -ne 0 ]]; then
+ echo "Fail to download ${MYSQL_DRIVER}."
+ exit 1
+fi
\ No newline at end of file
diff --git a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/ClusterE2E.java b/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/ClusterE2E.java
index 05a7704..e365860 100755
--- a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/ClusterE2E.java
+++ b/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/ClusterE2E.java
@@ -226,7 +226,7 @@ public class ClusterE2E extends SkyWalkingTestAdapter {
}
for (String metricName : ALL_ENDPOINT_MULTIPLE_LINEAR_METRICS) {
- verifyPercentileMetrics(graphql, metricName, endpoint.getKey(), startTime, 0, null);
+ verifyPercentileMetrics(graphql, metricName, endpoint.getKey(), startTime);
}
}
}
@@ -238,7 +238,7 @@ public class ClusterE2E extends SkyWalkingTestAdapter {
verifyMetrics(graphql, metricName, service.getKey(), startTime);
}
for (String metricName : ALL_SERVICE_MULTIPLE_LINEAR_METRICS) {
- verifyPercentileMetrics(graphql, metricName, service.getKey(), startTime, 0, null);
+ verifyPercentileMetrics(graphql, metricName, service.getKey(), startTime);
}
}
diff --git a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/base/SkyWalkingTestAdapter.java b/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/base/SkyWalkingTestAdapter.java
index 53e9d42..3f07569 100644
--- a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/base/SkyWalkingTestAdapter.java
+++ b/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/base/SkyWalkingTestAdapter.java
@@ -21,15 +21,15 @@ package org.apache.skywalking.e2e.base;
import com.google.common.collect.ImmutableMap;
import java.net.URL;
import java.time.LocalDateTime;
-import java.time.ZoneOffset;
import java.util.Map;
import org.apache.skywalking.e2e.SimpleQueryClient;
import org.apache.skywalking.e2e.common.HostAndPort;
+import org.apache.skywalking.e2e.utils.Times;
import org.springframework.web.client.RestTemplate;
public abstract class SkyWalkingTestAdapter {
protected final RestTemplate restTemplate = new RestTemplate();
- protected final LocalDateTime startTime = LocalDateTime.now(ZoneOffset.UTC);
+ protected final LocalDateTime startTime = Times.now();
protected Map<String, String> trafficData = ImmutableMap.of("name", "SkyWalking");
diff --git a/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/browser/BrowserE2E.java b/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/browser/BrowserE2E.java
new file mode 100644
index 0000000..dd31599
--- /dev/null
+++ b/test/e2e/e2e-test/src/test/java/org/apache/skywalking/e2e/browser/BrowserE2E.java
@@ -0,0 +1,290 @@
+/*
+ * 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.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
+ */
+
+package org.apache.skywalking.e2e.browser;
+
+import io.grpc.ManagedChannel;
+import io.grpc.internal.DnsNameResolverProvider;
+import io.grpc.netty.NettyChannelBuilder;
+import io.grpc.stub.StreamObserver;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.CountDownLatch;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.skywalking.apm.network.common.v3.Commands;
+import org.apache.skywalking.apm.network.language.agent.v3.BrowserPerfData;
+import org.apache.skywalking.apm.network.language.agent.v3.BrowserPerfServiceGrpc;
+import org.apache.skywalking.apm.network.language.agent.v3.ErrorCategory;
+import org.apache.skywalking.e2e.annotation.ContainerHostAndPort;
+import org.apache.skywalking.e2e.annotation.DockerCompose;
+import org.apache.skywalking.e2e.base.SkyWalkingE2E;
+import org.apache.skywalking.e2e.base.SkyWalkingTestAdapter;
+import org.apache.skywalking.e2e.base.TrafficController;
+import org.apache.skywalking.e2e.common.HostAndPort;
+import org.apache.skywalking.e2e.retryable.RetryableTest;
+import org.apache.skywalking.e2e.service.Service;
+import org.apache.skywalking.e2e.service.ServicesMatcher;
+import org.apache.skywalking.e2e.service.ServicesQuery;
+import org.apache.skywalking.e2e.service.endpoint.Endpoint;
+import org.apache.skywalking.e2e.service.endpoint.EndpointQuery;
+import org.apache.skywalking.e2e.service.endpoint.Endpoints;
+import org.apache.skywalking.e2e.service.endpoint.EndpointsMatcher;
+import org.apache.skywalking.e2e.service.instance.Instance;
+import org.apache.skywalking.e2e.service.instance.Instances;
+import org.apache.skywalking.e2e.service.instance.InstancesMatcher;
+import org.apache.skywalking.e2e.service.instance.InstancesQuery;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.testcontainers.containers.DockerComposeContainer;
+
+import static org.apache.skywalking.e2e.metrics.BrowserMetricsQuery.ALL_BROWSER_METRICS;
+import static org.apache.skywalking.e2e.metrics.BrowserMetricsQuery.ALL_BROWSER_PAGE_METRICS;
+import static org.apache.skywalking.e2e.metrics.BrowserMetricsQuery.ALL_BROWSER_PAGE_MULTIPLE_LINEAR_METRICS;
+import static org.apache.skywalking.e2e.metrics.BrowserMetricsQuery.ALL_BROWSER_SINGLE_VERSION_METRICS;
+import static org.apache.skywalking.e2e.metrics.MetricsMatcher.verifyMetrics;
+import static org.apache.skywalking.e2e.metrics.MetricsMatcher.verifyPercentileMetrics;
+import static org.apache.skywalking.e2e.utils.Times.now;
+import static org.apache.skywalking.e2e.utils.Yamls.load;
+
+@Slf4j
+@SkyWalkingE2E
+public class BrowserE2E extends SkyWalkingTestAdapter {
+ private static final int MAX_INBOUND_MESSAGE_SIZE = 1024 * 1024 * 50;
+
+ private static final String BROWSER_NAME = "e2e";
+
+ private static final String BROWSER_SINGLE_VERSION_NAME = "v1.0.0";
+
+ @SuppressWarnings("unused")
+ @DockerCompose({
+ "docker/browser/docker-compose.${SW_STORAGE}.yml",
+ })
+ private DockerComposeContainer<?> justForSideEffects;
+
+ @SuppressWarnings("unused")
+ @ContainerHostAndPort(name = "oap", port = 12800)
+ private HostAndPort swWebappHostPort;
+
+ @SuppressWarnings("unused")
+ @ContainerHostAndPort(name = "oap", port = 11800)
+ private HostAndPort oapHostPort;
+
+ private BrowserPerfServiceGrpc.BrowserPerfServiceStub browserPerfServiceStub;
+
+ @BeforeAll
+ public void setUp() {
+ queryClient(swWebappHostPort);
+
+ final ManagedChannel channel =
+ NettyChannelBuilder.forAddress(oapHostPort.host(), oapHostPort.port())
+ .nameResolverFactory(new DnsNameResolverProvider())
+ .maxInboundMessageSize(MAX_INBOUND_MESSAGE_SIZE)
+ .usePlaintext()
+ .build();
+
+ browserPerfServiceStub = BrowserPerfServiceGrpc.newStub(channel);
+
+ generateTraffic();
+ }
+
+ @AfterAll
+ public void tearDown() {
+ trafficController.stop();
+ }
+
+ @RetryableTest
+ public void verifyBrowserData() throws Exception {
+ final List<Service> services = graphql.browserServices(
+ new ServicesQuery().start(startTime).end(now()));
+ LOGGER.info("services: {}", services);
+
+ load("expected/browser/services.yml").as(ServicesMatcher.class).verify(services);
+
+ for (Service service : services) {
+ LOGGER.info("verifying service version: {}", service);
+ // browser metrics
+ verifyBrowserMetrics(service);
+
+ // browser single version
+ verifyBrowserSingleVersion(service);
+
+ // browser page path
+ verifyBrowserPagePath(service);
+ }
+ }
+
+ @RetryableTest
+ public void errorLogs() throws Exception {
+ List<BrowserErrorLog> logs = graphql.browserErrorLogs(new BrowserErrorLogQuery().start(startTime).end(now()));
+
+ LOGGER.info("errorLogs: {}", logs);
+
+ load("expected/browser/error-log.yml").as(BrowserErrorLogsMatcher.class).verifyLoosely(logs);
+ }
+
+ private void verifyBrowserMetrics(final Service service) throws Exception {
+ for (String metricName : ALL_BROWSER_METRICS) {
+ verifyMetrics(graphql, metricName, service.getKey(), startTime);
+ }
+ }
+
+ private void verifyBrowserSingleVersion(final Service service) throws Exception {
+ Instances instances = graphql.instances(
+ new InstancesQuery().serviceId(service.getKey()).start(startTime).end(now())
+ );
+ LOGGER.info("instances: {}", instances);
+ load("expected/browser/version.yml").as(InstancesMatcher.class).verify(instances);
+ // service version metrics
+ for (Instance instance : instances.getInstances()) {
+ verifyBrowserSingleVersionMetrics(instance);
+ }
+ }
+
+ private void verifyBrowserSingleVersionMetrics(Instance instance) throws Exception {
+ for (String metricName : ALL_BROWSER_SINGLE_VERSION_METRICS) {
+ verifyMetrics(graphql, metricName, instance.getKey(), startTime);
+ }
+ }
+
+ private void verifyBrowserPagePath(final Service service) throws Exception {
+ Endpoints endpoints = graphql.endpoints(new EndpointQuery().serviceId(String.valueOf(service.getKey())));
+ LOGGER.info("endpoints: {}", endpoints);
+ load("expected/browser/page-path.yml").as(EndpointsMatcher.class).verify(endpoints);
+ // service page metrics
+ for (Endpoint endpoint : endpoints.getEndpoints()) {
+ verifyBrowserPagePathMetrics(endpoint);
+ }
+ }
+
+ private void verifyBrowserPagePathMetrics(Endpoint endpoint) throws Exception {
+ for (String metricName : ALL_BROWSER_PAGE_METRICS) {
+ verifyMetrics(graphql, metricName, endpoint.getKey(), startTime);
+ }
+
+ for (String metricName : ALL_BROWSER_PAGE_MULTIPLE_LINEAR_METRICS) {
+ verifyPercentileMetrics(graphql, metricName, endpoint.getKey(), startTime);
+ }
+ }
+
+ private void generateTraffic() {
+ trafficController = TrafficController.builder()
+ .sender(this::sendBrowserData)
+ .build()
+ .start();
+ }
+
+ private boolean sendBrowserData() {
+ try {
+ BrowserPerfData.Builder builder = BrowserPerfData.newBuilder()
+ .setService(BROWSER_NAME)
+ .setServiceVersion(BROWSER_SINGLE_VERSION_NAME)
+ .setPagePath("/e2e-browser")
+ .setRedirectTime(10)
+ .setDnsTime(10)
+ .setTtfbTime(10)
+ .setTcpTime(10)
+ .setTransTime(10)
+ .setDomAnalysisTime(10)
+ .setFptTime(10)
+ .setDomReadyTime(10)
+ .setLoadPageTime(10)
+ .setResTime(10)
+ .setSslTime(10)
+ .setTtlTime(10)
+ .setFirstPackTime(10)
+ .setFmpTime(10);
+
+ sendBrowserPerfData(builder.build());
+
+ for (ErrorCategory category : ErrorCategory.values()) {
+ if (category == ErrorCategory.UNRECOGNIZED) {
+ continue;
+ }
+ org.apache.skywalking.apm.network.language.agent.v3.BrowserErrorLog.Builder errorLogBuilder = org.apache.skywalking.apm.network.language.agent.v3.BrowserErrorLog
+ .newBuilder()
+ .setUniqueId(UUID.randomUUID().toString())
+ .setService(BROWSER_NAME)
+ .setServiceVersion(BROWSER_SINGLE_VERSION_NAME)
+ .setPagePath("/e2e-browser")
+ .setCategory(category)
+ .setMessage("test")
+ .setLine(1)
+ .setCol(1)
+ .setStack("e2e")
+ .setErrorUrl("/e2e-browser");
+ if (category == ErrorCategory.js) {
+ errorLogBuilder.setFirstReportedError(true);
+ }
+ sendBrowserErrorLog(errorLogBuilder.build());
+ }
+ return true;
+ } catch (Exception e) {
+ LOGGER.warn(e.getMessage(), e);
+ return false;
+ }
+ }
+
+ private void sendBrowserPerfData(BrowserPerfData browserPerfData) throws InterruptedException {
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ browserPerfServiceStub.collectPerfData(browserPerfData, new StreamObserver<Commands>() {
+ @Override
+ public void onNext(Commands commands) {
+
+ }
+
+ @Override
+ public void onError(Throwable throwable) {
+ throwable.printStackTrace();
+ latch.countDown();
+ }
+
+ @Override
+ public void onCompleted() {
+ latch.countDown();
+ }
+ });
+ latch.await();
+ }
+
+ private void sendBrowserErrorLog(org.apache.skywalking.apm.network.language.agent.v3.BrowserErrorLog browserErrorLog) throws InterruptedException {
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ StreamObserver<org.apache.skywalking.apm.network.language.agent.v3.BrowserErrorLog> collectStream = browserPerfServiceStub
+ .collectErrorLogs(
+ new StreamObserver<Commands>() {
+ @Override
+ public void onNext(Commands commands) {
+
+ }
+
+ @Override
+ public void onError(Throwable throwable) {
+ throwable.printStackTrace();
+ latch.countDown();
+ }
+
+ @Override
+ public void onCompleted() {
+ latch.countDown();
+ }
+ });
+ collectStream.onNext(browserErrorLog);
+ collectStream.onCompleted();
+ latch.await();
+ }
+}
diff --git a/test/e2e/e2e-test/src/test/resources/expected/browser/error-log.yml b/test/e2e/e2e-test/src/test/resources/expected/browser/error-log.yml
new file mode 100644
index 0000000..0631f79
--- /dev/null
+++ b/test/e2e/e2e-test/src/test/resources/expected/browser/error-log.yml
@@ -0,0 +1,28 @@
+# 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.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# 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.
+
+logs:
+ - service: "e2e"
+ serviceVersion: "v1.0.0"
+ time: not null
+ pagePath: "/e2e-browser"
+ category: not null
+ grade: not null
+ message: "test"
+ line: 1
+ col: 1
+ stack: "e2e"
+ errorUrl: "/e2e-browser"
+ firstReportedError: not null
\ No newline at end of file
diff --git a/test/e2e/e2e-test/src/test/resources/expected/browser/page-path.yml b/test/e2e/e2e-test/src/test/resources/expected/browser/page-path.yml
new file mode 100644
index 0000000..5112247
--- /dev/null
+++ b/test/e2e/e2e-test/src/test/resources/expected/browser/page-path.yml
@@ -0,0 +1,18 @@
+# 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.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# 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.
+
+endpoints:
+ - key: ZTJl.0_L2UyZS1icm93c2Vy
+ label: /e2e-browser
\ No newline at end of file
diff --git a/test/e2e/e2e-test/src/test/resources/expected/browser/services.yml b/test/e2e/e2e-test/src/test/resources/expected/browser/services.yml
new file mode 100644
index 0000000..37e86cb
--- /dev/null
+++ b/test/e2e/e2e-test/src/test/resources/expected/browser/services.yml
@@ -0,0 +1,18 @@
+# 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.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# 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.
+
+services:
+ - key: ZTJl.0
+ label: "e2e"
\ No newline at end of file
diff --git a/test/e2e/e2e-test/src/test/resources/expected/browser/version.yml b/test/e2e/e2e-test/src/test/resources/expected/browser/version.yml
new file mode 100644
index 0000000..b868b15
--- /dev/null
+++ b/test/e2e/e2e-test/src/test/resources/expected/browser/version.yml
@@ -0,0 +1,18 @@
+# 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.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# 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.
+
+instances:
+ - key: ZTJl.0_djEuMC4w
+ label: not null
\ No newline at end of file
diff --git a/test/e2e/pom.xml b/test/e2e/pom.xml
index eb1d9cb..d206cdb 100644
--- a/test/e2e/pom.xml
+++ b/test/e2e/pom.xml
@@ -169,6 +169,10 @@
**/*.yaml,
**/*.xml
</resourceIncludes>
+ <resourceExcludes>
+ **/.asf.yaml,
+ **/.github/**
+ </resourceExcludes>
<propertyExpansion>
import.control=${maven.multiModuleProjectDirectory}/apm-checkstyle/importControl.xml
</propertyExpansion>