├── .gitattributes ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .github ├── pull_request_template.md ├── CODEOWNERS └── workflows │ ├── trivy-scan.yml │ ├── build-timestamped-master.yml │ ├── daily-build.yml │ ├── pull-request.yml │ ├── publish-release.yml │ └── central-publish.yml ├── codecov.yml ├── ballerina ├── modules │ └── mockextension │ │ ├── README.md │ │ ├── tracing.bal │ │ └── metrics.bal ├── Dependencies.toml ├── annotations.bal ├── Ballerina.toml ├── build.gradle ├── commons.bal └── README.md ├── native ├── src │ └── main │ │ ├── resources │ │ └── META-INF │ │ │ ├── native-image │ │ │ └── io.ballerina.stdlib │ │ │ │ └── observe-native │ │ │ │ ├── resource-config.json │ │ │ │ └── reflect-config.json │ │ │ └── services │ │ │ └── io.ballerina.runtime.observability.tracer.spi.TracerProvider │ │ └── java │ │ ├── module-info.java │ │ └── io │ │ └── ballerina │ │ └── stdlib │ │ └── observe │ │ ├── nativeimpl │ │ ├── AddTag.java │ │ ├── CounterReset.java │ │ ├── GaugeGetValue.java │ │ ├── GaugeSetValue.java │ │ ├── GaugeUnregister.java │ │ ├── GaugeIncrement.java │ │ ├── GaugeDecrement.java │ │ ├── CounterGetValue.java │ │ ├── CounterUnregister.java │ │ ├── CounterIncrement.java │ │ ├── AddTagToSpan.java │ │ ├── StartRootSpan.java │ │ ├── GaugeGetSnapshot.java │ │ ├── CounterInitialize.java │ │ ├── GetTagValue.java │ │ ├── GaugeRegister.java │ │ ├── CounterRegister.java │ │ ├── StartSpan.java │ │ ├── AddTagToMetrics.java │ │ ├── FinishSpan.java │ │ ├── GetSpanContext.java │ │ ├── ObserveNativeImplConstants.java │ │ ├── GaugeInitialize.java │ │ ├── GetAllMetrics.java │ │ ├── LookupMetric.java │ │ ├── Utils.java │ │ └── OpenTracerBallerinaWrapper.java │ │ ├── mockextension │ │ ├── model │ │ │ ├── MockCounter.java │ │ │ ├── MockPolledGauge.java │ │ │ ├── MockMetric.java │ │ │ ├── MockGauge.java │ │ │ └── Metrics.java │ │ ├── MockTracerUtils.java │ │ ├── typeadapter │ │ │ └── DurationTypeAdapter.java │ │ ├── BMockTracerProvider.java │ │ ├── MetricsUtils.java │ │ └── BMockSpan.java │ │ └── ObservabilitySystemPackageRepositoryProvider.java ├── spotbugs-exclude.xml └── build.gradle ├── .gitignore ├── issue_template.md ├── gradle.properties ├── ballerina-tests ├── src │ └── test │ │ ├── resources │ │ ├── testng.xml │ │ ├── logging.properties │ │ └── test-src │ │ │ ├── counter_test.bal │ │ │ ├── metrics_registry_test.bal │ │ │ └── summary_test.bal │ │ └── java │ │ └── io │ │ └── ballerina │ │ └── stdlib │ │ └── observe │ │ ├── MetricTest.java │ │ ├── CounterTest.java │ │ ├── SummaryTest.java │ │ └── RegistryTest.java └── build.gradle ├── settings.gradle ├── pull_request_template.md ├── gradlew.bat ├── README.md ├── gradlew └── LICENSE /.gitattributes: -------------------------------------------------------------------------------- 1 | # Ensure all Java files use LF. 2 | *.java eol=lf 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerina-observe/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Purpose 2 | 3 | ## Examples 4 | 5 | ## Checklist 6 | - [ ] Linked to an issue 7 | - [ ] Updated the changelog 8 | - [ ] Added tests -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | fixes: 2 | - "ballerina/observe/*/::ballerina/" 3 | - "ballerina/observe$0046mockextension/*/::ballerina/modules/mockextension" 4 | 5 | ignore: 6 | - "**/tests" 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Lines starting with '#' are comments. 2 | # Each line is a file pattern followed by one or more owners. 3 | 4 | # See: https://help.github.com/articles/about-codeowners/ 5 | 6 | # These owners will be the default owners for everything in the repo. 7 | * @chathurace @NipunaMadhushan @keizer619 8 | -------------------------------------------------------------------------------- /ballerina/modules/mockextension/README.md: -------------------------------------------------------------------------------- 1 | ## Module Overview 2 | 3 | This module provides an API for accessing observability mock functionality. 4 | 5 | Following functions are provided. 6 | 7 | ```ballerina 8 | var metrics = mockextension:getMetrics(); 9 | 10 | var spans = mockextension:getFinishedSpans(); 11 | ``` 12 | -------------------------------------------------------------------------------- /native/src/main/resources/META-INF/native-image/io.ballerina.stdlib/observe-native/resource-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "resources": { 3 | "includes": [ 4 | { 5 | "pattern": "\\QMETA-INF/services/io.ballerina.runtime.observability.metrics.spi.MetricProvider\\E" 6 | }, 7 | { 8 | "pattern": "\\QMETA-INF/services/io.opentelemetry.context.ContextStorageProvider\\E" 9 | } 10 | ] 11 | }, 12 | "bundles": [] 13 | } 14 | -------------------------------------------------------------------------------- /native/src/main/java/module-info.java: -------------------------------------------------------------------------------- 1 | module io.ballerina.observability { 2 | requires com.google.gson; 3 | requires io.ballerina.lang; 4 | requires io.ballerina.runtime; 5 | requires io.opentelemetry.api; 6 | requires io.opentelemetry.sdk.testing; 7 | requires io.opentelemetry.sdk.trace; 8 | requires io.opentelemetry.context; 9 | requires slf4j.jdk14; 10 | requires slf4j.api; 11 | 12 | provides io.ballerina.runtime.observability.tracer.spi.TracerProvider 13 | with io.ballerina.stdlib.observe.mockextension.BMockTracerProvider; 14 | } 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | !gradle/wrapper/gradle-wrapper.jar 15 | *.jar 16 | *.war 17 | *.nar 18 | *.ear 19 | *.zip 20 | *.tar.gz 21 | *.rar 22 | 23 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 24 | hs_err_pid* 25 | 26 | # Java related ignores 27 | build/ 28 | target/ 29 | .gradle/ 30 | 31 | # MacOS 32 | *.DS_Store 33 | 34 | # IDE-related files 35 | .idea 36 | *.iml 37 | *.ipr 38 | *.iws 39 | .code 40 | .project 41 | .settings 42 | .vscode 43 | 44 | # Ballerina related ignores 45 | Ballerina.lock 46 | velocity.log* 47 | **/bin 48 | **/lib 49 | **/.settings 50 | Dependencies.toml 51 | -------------------------------------------------------------------------------- /native/src/main/resources/META-INF/native-image/io.ballerina.stdlib/observe-native/reflect-config.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "org.HdrHistogram.ConcurrentHistogram", 4 | "methods": [ 5 | { 6 | "name": "", 7 | "parameterTypes": [ 8 | "long", 9 | "long", 10 | "int" 11 | ] 12 | }, 13 | { 14 | "name": "", 15 | "parameterTypes": [ 16 | "org.HdrHistogram.AbstractHistogram" 17 | ] 18 | } 19 | ] 20 | }, 21 | { 22 | "name": "org.HdrHistogram.Histogram", 23 | "methods": [ 24 | { 25 | "name": "", 26 | "parameterTypes": [ 27 | "long", 28 | "long", 29 | "int" 30 | ] 31 | } 32 | ] 33 | } 34 | ] 35 | -------------------------------------------------------------------------------- /native/src/main/resources/META-INF/services/io.ballerina.runtime.observability.tracer.spi.TracerProvider: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020, WSO2 Inc. (http://wso2.com) All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | io.ballerina.stdlib.observe.mockextension.BMockTracerProvider 16 | -------------------------------------------------------------------------------- /ballerina/Dependencies.toml: -------------------------------------------------------------------------------- 1 | # AUTO-GENERATED FILE. DO NOT MODIFY. 2 | 3 | # This file is auto-generated by Ballerina for managing dependency versions. 4 | # It should not be modified by hand. 5 | 6 | [ballerina] 7 | dependencies-toml-version = "2" 8 | distribution-version = "2201.13.0" 9 | 10 | [[package]] 11 | org = "ballerina" 12 | name = "jballerina.java" 13 | version = "0.0.0" 14 | modules = [ 15 | {org = "ballerina", packageName = "jballerina.java", moduleName = "jballerina.java"} 16 | ] 17 | 18 | [[package]] 19 | org = "ballerina" 20 | name = "observe" 21 | version = "1.7.0" 22 | dependencies = [ 23 | {org = "ballerina", name = "jballerina.java"} 24 | ] 25 | modules = [ 26 | {org = "ballerina", packageName = "observe", moduleName = "observe"}, 27 | {org = "ballerina", packageName = "observe", moduleName = "observe.mockextension"} 28 | ] 29 | 30 | -------------------------------------------------------------------------------- /issue_template.md: -------------------------------------------------------------------------------- 1 | **Description:** 2 | 3 | 4 | **Suggested Labels:** 5 | 6 | 7 | **Suggested Assignees:** 8 | 9 | 10 | **Affected Product Version:** 11 | 12 | **OS, DB, other environment details and versions:** 13 | 14 | **Steps to reproduce:** 15 | 16 | 17 | **Related Issues:** 18 | -------------------------------------------------------------------------------- /.github/workflows/trivy-scan.yml: -------------------------------------------------------------------------------- 1 | name: Trivy 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: '0 0 * * *' 7 | 8 | jobs: 9 | ubuntu-build: 10 | name: Build on Ubuntu 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Set up JDK 21 15 | uses: actions/setup-java@v2 16 | with: 17 | distribution: 'adopt' 18 | java-version: 21 19 | - name: Build with Gradle 20 | env: 21 | packageUser: ${{ github.actor }} 22 | packagePAT: ${{ secrets.GITHUB_TOKEN }} 23 | run: ./gradlew build -x check -x test --stacktrace --console=plain 24 | - name: Run Trivy vulnerability scanner 25 | uses: aquasecurity/trivy-action@master 26 | with: 27 | scan-type: 'fs' 28 | scan-ref: '/github/workspace/ballerina/lib' 29 | format: 'table' 30 | exit-code: '1' 31 | -------------------------------------------------------------------------------- /ballerina/annotations.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | # This is used for making a function observable. 18 | # Can be applied to functions which are not observable by default to make them observable. 19 | # 20 | public const annotation Observable on source function; 21 | -------------------------------------------------------------------------------- /ballerina/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | org = "ballerina" 3 | name = "observe" 4 | version = "1.7.0" 5 | distribution = "2201.13.0" 6 | 7 | [[package.modules]] 8 | name = "observe.mockextension" 9 | description = "This module provides mock extension to observe Ballerina applications." 10 | export = true 11 | 12 | [platform.java21] 13 | graalvmCompatible = true 14 | 15 | [[platform.java21.dependency]] 16 | path = "../native/build/libs/observe-native-1.7.0.jar" 17 | groupId = "ballerina" 18 | artifactId = "observe" 19 | 20 | [[platform.java21.dependency]] 21 | groupId = "io.opentelemetry" 22 | artifactId = "opentelemetry-sdk-trace" 23 | version = "1.0.0" 24 | 25 | [[platform.java21.dependency]] 26 | groupId = "io.opentelemetry" 27 | artifactId = "opentelemetry-sdk-testing" 28 | version = "1.0.0" 29 | 30 | [[platform.java21.dependency]] 31 | groupId = "io.opentelemetry" 32 | artifactId = "opentelemetry-sdk-common" 33 | version = "1.0.0" 34 | 35 | [[platform.java21.dependency]] 36 | groupId = "io.opentelemetry" 37 | artifactId = "opentelemetry-semconv" 38 | version = "1.0.0-alpha" 39 | -------------------------------------------------------------------------------- /native/spotbugs-exclude.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/nativeimpl/AddTag.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025, WSO2 LLC. (http://wso2.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.ballerina.stdlib.observe.nativeimpl; 18 | 19 | import io.ballerina.runtime.api.values.BString; 20 | import io.ballerina.runtime.observability.ObserveUtils; 21 | 22 | public class AddTag { 23 | public static void addTag(BString tagKey, BString tagValue) { 24 | if (ObserveUtils.isObservabilityEnabled()) { 25 | ObserveUtils.addTag(tagKey.getValue(), tagValue.getValue()); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | org.gradle.caching=true 16 | group=io.ballerina.stdlib 17 | version=1.7.1-SNAPSHOT 18 | ballerinaLangVersion=2201.13.0 19 | 20 | spotbugsPluginVersion=6.0.18 21 | shadowJarPluginVersion=8.1.1 22 | downloadPluginVersion=5.4.0 23 | releasePluginVersion=2.8.0 24 | ballerinaTomlParserVersion=1.2.2 25 | ballerinaGradlePluginVersion=2.3.0 26 | checkstylePluginVersion=10.12.1 27 | openTelemetryVersion=1.0.0 28 | gsonVersion=2.8.9 29 | 30 | # Test Dependency Versions 31 | testngVersion=7.7.0 32 | slf4jVersion=1.7.26 33 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/mockextension/model/MockCounter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.stdlib.observe.mockextension.model; 20 | 21 | /** 22 | * Class for holding counter related metrics data. 23 | */ 24 | public class MockCounter extends MockMetric { 25 | private long value; 26 | 27 | public long getValue() { 28 | return value; 29 | } 30 | 31 | public void setValue(long value) { 32 | this.value = value; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/mockextension/model/MockPolledGauge.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.stdlib.observe.mockextension.model; 20 | 21 | /** 22 | * Class for holding polled gauge related metrics data. 23 | */ 24 | public class MockPolledGauge extends MockMetric { 25 | private double value; 26 | 27 | public double getValue() { 28 | return value; 29 | } 30 | 31 | public void setValue(double value) { 32 | this.value = value; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/mockextension/model/MockMetric.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.stdlib.observe.mockextension.model; 20 | 21 | import io.ballerina.runtime.observability.metrics.MetricId; 22 | 23 | /** 24 | * Abstract class containing the common data of a metric. 25 | */ 26 | public abstract class MockMetric { 27 | private MetricId id; 28 | 29 | public MetricId getId() { 30 | return id; 31 | } 32 | 33 | public void setId(MetricId id) { 34 | this.id = id; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/nativeimpl/CounterReset.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * WSO2 Inc. licenses this file to you under the Apache License, 4 | * Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, 11 | * software distributed under the License is distributed on an 12 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | * KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations 15 | * under the License. 16 | * 17 | */ 18 | package io.ballerina.stdlib.observe.nativeimpl; 19 | 20 | import io.ballerina.runtime.api.values.BObject; 21 | import io.ballerina.runtime.observability.metrics.Counter; 22 | 23 | /** 24 | * This is the native reset function implementation of the Counter object. 25 | * 26 | * @since 0.980.0 27 | */ 28 | 29 | public class CounterReset { 30 | 31 | public static void reset(BObject counterObj) { 32 | Counter counter = (Counter) counterObj.getNativeData(ObserveNativeImplConstants.METRIC_NATIVE_INSTANCE_KEY); 33 | counter.reset(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/nativeimpl/GaugeGetValue.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * WSO2 Inc. licenses this file to you under the Apache License, 4 | * Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, 11 | * software distributed under the License is distributed on an 12 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | * KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations 15 | * under the License. 16 | * 17 | */ 18 | package io.ballerina.stdlib.observe.nativeimpl; 19 | 20 | import io.ballerina.runtime.api.values.BObject; 21 | import io.ballerina.runtime.observability.metrics.Gauge; 22 | 23 | /** 24 | * This is the native getValue function implementation of the Gauge object. 25 | * 26 | * @since 0.980.0 27 | */ 28 | 29 | public class GaugeGetValue { 30 | 31 | public static double getValue(BObject guage) { 32 | Gauge counter = (Gauge) guage.getNativeData(ObserveNativeImplConstants.METRIC_NATIVE_INSTANCE_KEY); 33 | return counter.getValue(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/nativeimpl/GaugeSetValue.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * WSO2 Inc. licenses this file to you under the Apache License, 4 | * Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, 11 | * software distributed under the License is distributed on an 12 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | * KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations 15 | * under the License. 16 | * 17 | */ 18 | package io.ballerina.stdlib.observe.nativeimpl; 19 | 20 | import io.ballerina.runtime.api.values.BObject; 21 | import io.ballerina.runtime.observability.metrics.Gauge; 22 | 23 | /** 24 | * This is the nativeSetValue function implementation of the Gauge object. 25 | * 26 | * @since 0.980.0 27 | */ 28 | 29 | public class GaugeSetValue { 30 | 31 | public static void setValue(BObject guage, double amount) { 32 | Gauge gauge = (Gauge) guage.getNativeData(ObserveNativeImplConstants.METRIC_NATIVE_INSTANCE_KEY); 33 | gauge.setValue(amount); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/nativeimpl/GaugeUnregister.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * WSO2 Inc. licenses this file to you under the Apache License, 4 | * Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, 11 | * software distributed under the License is distributed on an 12 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | * KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations 15 | * under the License. 16 | * 17 | */ 18 | package io.ballerina.stdlib.observe.nativeimpl; 19 | 20 | import io.ballerina.runtime.api.values.BObject; 21 | import io.ballerina.runtime.observability.metrics.Gauge; 22 | 23 | /** 24 | * This is the native register function implementation of the Counter object. 25 | * 26 | * @since 0.980.0 27 | */ 28 | 29 | public class GaugeUnregister { 30 | 31 | public static void unregister(BObject guageObj) { 32 | Gauge gauge = (Gauge) guageObj.getNativeData(ObserveNativeImplConstants.METRIC_NATIVE_INSTANCE_KEY); 33 | gauge.unregister(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /ballerina-tests/src/test/resources/testng.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/nativeimpl/GaugeIncrement.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * WSO2 Inc. licenses this file to you under the Apache License, 4 | * Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, 11 | * software distributed under the License is distributed on an 12 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | * KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations 15 | * under the License. 16 | * 17 | */ 18 | package io.ballerina.stdlib.observe.nativeimpl; 19 | 20 | import io.ballerina.runtime.api.values.BObject; 21 | import io.ballerina.runtime.observability.metrics.Gauge; 22 | 23 | /** 24 | * This is the nativeIncrement function implementation of the Gauge object. 25 | * 26 | * @since 0.980.0 27 | */ 28 | 29 | public class GaugeIncrement { 30 | 31 | public static void increment(BObject guage, double amount) { 32 | Gauge gauge = (Gauge) guage.getNativeData(ObserveNativeImplConstants.METRIC_NATIVE_INSTANCE_KEY); 33 | gauge.increment(amount); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/nativeimpl/GaugeDecrement.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * WSO2 Inc. licenses this file to you under the Apache License, 4 | * Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, 11 | * software distributed under the License is distributed on an 12 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | * KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations 15 | * under the License. 16 | * 17 | */ 18 | package io.ballerina.stdlib.observe.nativeimpl; 19 | 20 | import io.ballerina.runtime.api.values.BObject; 21 | import io.ballerina.runtime.observability.metrics.Gauge; 22 | 23 | /** 24 | * This is the native decrement function implementation of the Gauge object. 25 | * 26 | * @since 0.980.0 27 | */ 28 | 29 | public class GaugeDecrement { 30 | 31 | public static void decrement(BObject guage, double amount) { 32 | Gauge gauge = (Gauge) guage.getNativeData(ObserveNativeImplConstants.METRIC_NATIVE_INSTANCE_KEY); 33 | gauge.decrement(amount); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/nativeimpl/CounterGetValue.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * WSO2 Inc. licenses this file to you under the Apache License, 4 | * Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, 11 | * software distributed under the License is distributed on an 12 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | * KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations 15 | * under the License. 16 | * 17 | */ 18 | package io.ballerina.stdlib.observe.nativeimpl; 19 | 20 | import io.ballerina.runtime.api.values.BObject; 21 | import io.ballerina.runtime.observability.metrics.Counter; 22 | 23 | /** 24 | * This is the getValue function native implementation of the Counter object. 25 | * 26 | * @since 0.980.0 27 | */ 28 | 29 | public class CounterGetValue { 30 | 31 | public static long getValue(BObject counterObj) { 32 | Counter counter = (Counter) counterObj.getNativeData(ObserveNativeImplConstants.METRIC_NATIVE_INSTANCE_KEY); 33 | return counter.getValue(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/nativeimpl/CounterUnregister.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * WSO2 Inc. licenses this file to you under the Apache License, 4 | * Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, 11 | * software distributed under the License is distributed on an 12 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | * KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations 15 | * under the License. 16 | * 17 | */ 18 | package io.ballerina.stdlib.observe.nativeimpl; 19 | 20 | import io.ballerina.runtime.api.values.BObject; 21 | import io.ballerina.runtime.observability.metrics.Counter; 22 | 23 | /** 24 | * This is the native register function implementation of the Counter object. 25 | * 26 | * @since 0.980.0 27 | */ 28 | 29 | public class CounterUnregister { 30 | 31 | public static void unregister(BObject counterObj) { 32 | Counter counter = (Counter) counterObj.getNativeData(ObserveNativeImplConstants.METRIC_NATIVE_INSTANCE_KEY); 33 | counter.unregister(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/nativeimpl/CounterIncrement.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * WSO2 Inc. licenses this file to you under the Apache License, 4 | * Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, 11 | * software distributed under the License is distributed on an 12 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | * KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations 15 | * under the License. 16 | * 17 | */ 18 | package io.ballerina.stdlib.observe.nativeimpl; 19 | 20 | import io.ballerina.runtime.api.values.BObject; 21 | import io.ballerina.runtime.observability.metrics.Counter; 22 | 23 | /** 24 | * This is the native increment function implementation of the Counter object. 25 | * 26 | * @since 0.980.0 27 | */ 28 | 29 | public class CounterIncrement { 30 | 31 | public static void increment(BObject counterObj, long amount) { 32 | Counter counter = (Counter) counterObj.getNativeData(ObserveNativeImplConstants.METRIC_NATIVE_INSTANCE_KEY); 33 | counter.increment(amount); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/nativeimpl/AddTagToSpan.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | * 18 | */ 19 | 20 | package io.ballerina.stdlib.observe.nativeimpl; 21 | 22 | import io.ballerina.runtime.api.Environment; 23 | import io.ballerina.runtime.api.values.BString; 24 | 25 | /** 26 | * This function adds tags to a span. 27 | */ 28 | public class AddTagToSpan { 29 | private static final OpenTracerBallerinaWrapper otWrapperInstance = OpenTracerBallerinaWrapper.getInstance(); 30 | 31 | public static Object addTagToSpan(Environment env, BString tagKey, BString tagValue, long spanId) { 32 | return otWrapperInstance.addTag(env, tagKey.getValue(), tagValue.getValue(), spanId); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/nativeimpl/StartRootSpan.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | * 18 | */ 19 | 20 | package io.ballerina.stdlib.observe.nativeimpl; 21 | 22 | import io.ballerina.runtime.api.Environment; 23 | import io.ballerina.runtime.api.values.BMap; 24 | import io.ballerina.runtime.api.values.BString; 25 | 26 | /** 27 | * This function which implements the startSpan method for observe. 28 | */ 29 | 30 | public class StartRootSpan { 31 | 32 | public static long startRootSpan(Environment env, BString spanName, Object tags) { 33 | 34 | return OpenTracerBallerinaWrapper.getInstance().startSpan(env, 35 | spanName.getValue(), Utils.toStringMap((BMap) tags), 36 | OpenTracerBallerinaWrapper.ROOT_SPAN_INDICATOR); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ballerina-tests/src/test/java/io/ballerina/stdlib/observe/MetricTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | package io.ballerina.stdlib.observe; 19 | 20 | import io.ballerina.runtime.observability.metrics.DefaultMetricRegistry; 21 | import io.ballerina.runtime.observability.metrics.MetricRegistry; 22 | import org.ballerinalang.observe.metrics.extension.defaultimpl.DefaultMetricProvider; 23 | import org.testng.annotations.BeforeSuite; 24 | 25 | /** 26 | * This is the bases test class which enables the metrics reporting. 27 | * 28 | * @since 0.980.0 29 | */ 30 | public class MetricTest { 31 | 32 | @BeforeSuite 33 | public void init() { 34 | DefaultMetricProvider metricProvider = new DefaultMetricProvider(); 35 | metricProvider.init(); 36 | DefaultMetricRegistry.setInstance(new MetricRegistry(metricProvider)); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /.github/workflows/build-timestamped-master.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | if: github.repository_owner == 'ballerina-platform' 13 | steps: 14 | - name: Checkout Repository 15 | uses: actions/checkout@v2 16 | - name: Set up JDK 21 17 | uses: actions/setup-java@v2 18 | with: 19 | distribution: 'adopt' 20 | java-version: 21 21 | - name: Change to Timestamped Version 22 | run: | 23 | startTime=$(TZ="Asia/Kolkata" date +'%Y%m%d-%H%M00') 24 | latestCommit=$(git log -n 1 --pretty=format:"%h") 25 | VERSION=$((grep -w 'version' | cut -d= -f2) < gradle.properties | rev | cut --complement -d- -f1 | rev) 26 | updatedVersion=$VERSION-$startTime-$latestCommit 27 | echo $updatedVersion 28 | sed -i "s/version=\(.*\)/version=$updatedVersion/g" gradle.properties 29 | - name: Grant execute permission for gradlew 30 | run: chmod +x gradlew 31 | - name: Build with Gradle 32 | env: 33 | packageUser: ${{ secrets.BALLERINA_BOT_USERNAME }} 34 | packagePAT: ${{ secrets.BALLERINA_BOT_TOKEN }} 35 | publishUser: ${{ secrets.BALLERINA_BOT_USERNAME }} 36 | publishPAT: ${{ secrets.BALLERINA_BOT_TOKEN }} 37 | run: | 38 | ./gradlew publish --scan --no-daemon --stacktrace --console=plain 39 | - name: Generate CodeCov Report 40 | uses: codecov/codecov-action@v2 41 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/nativeimpl/GaugeGetSnapshot.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * WSO2 Inc. licenses this file to you under the Apache License, 4 | * Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, 11 | * software distributed under the License is distributed on an 12 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | * KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations 15 | * under the License. 16 | * 17 | */ 18 | package io.ballerina.stdlib.observe.nativeimpl; 19 | 20 | import io.ballerina.runtime.api.Environment; 21 | import io.ballerina.runtime.api.values.BObject; 22 | import io.ballerina.runtime.observability.metrics.Gauge; 23 | import io.ballerina.runtime.observability.metrics.Snapshot; 24 | 25 | /** 26 | * This is the getSnapshot extern function implementation of the Gauge object. 27 | * 28 | * @since 0.980.0 29 | */ 30 | 31 | public class GaugeGetSnapshot { 32 | 33 | public static Object getSnapshot(Environment env, BObject guageObj) { 34 | Gauge gauge = (Gauge) guageObj.getNativeData(ObserveNativeImplConstants.METRIC_NATIVE_INSTANCE_KEY); 35 | Snapshot[] snapshots = gauge.getSnapshots(); 36 | return Utils.createBSnapshots(env, snapshots); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/ObservabilitySystemPackageRepositoryProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | * 18 | */ 19 | 20 | package io.ballerina.stdlib.observe; 21 | 22 | import org.ballerinalang.annotation.JavaSPIService; 23 | import org.ballerinalang.spi.SystemPackageRepositoryProvider; 24 | import org.wso2.ballerinalang.compiler.packaging.repo.JarRepo; 25 | import org.wso2.ballerinalang.compiler.packaging.repo.Repo; 26 | 27 | /** 28 | * This represents the standard Ballerina built-in system package repository provider. 29 | * 30 | * @since 0.94 31 | */ 32 | @JavaSPIService("org.ballerinalang.spi.SystemPackageRepositoryProvider") 33 | public class ObservabilitySystemPackageRepositoryProvider implements SystemPackageRepositoryProvider { 34 | 35 | @Override 36 | public Repo loadRepository() { 37 | return new JarRepo(SystemPackageRepositoryProvider.getClassUri(this)); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/nativeimpl/CounterInitialize.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * WSO2 Inc. licenses this file to you under the Apache License, 4 | * Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, 11 | * software distributed under the License is distributed on an 12 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | * KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations 15 | * under the License. 16 | * 17 | */ 18 | package io.ballerina.stdlib.observe.nativeimpl; 19 | 20 | import io.ballerina.runtime.api.values.BMap; 21 | import io.ballerina.runtime.api.values.BObject; 22 | import io.ballerina.runtime.observability.metrics.Counter; 23 | 24 | /** 25 | * This is the native initialize function that's getting called when instantiating the Counter object. 26 | * 27 | * @since 0.980.0 28 | */ 29 | public class CounterInitialize { 30 | 31 | public static void initialize(BObject counterObj) { 32 | Counter counter = Counter.builder(counterObj.get(ObserveNativeImplConstants.NAME_FIELD).toString()) 33 | .description(counterObj.get(ObserveNativeImplConstants.DESCRIPTION_FIELD).toString()) 34 | .tags(Utils.toStringMap((BMap) counterObj.get(ObserveNativeImplConstants.TAGS_FIELD))) 35 | .build(); 36 | counterObj.addNativeData(ObserveNativeImplConstants.METRIC_NATIVE_INSTANCE_KEY, counter); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/nativeimpl/GetTagValue.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025, WSO2 LLC. (http://wso2.com). 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.ballerina.stdlib.observe.nativeimpl; 18 | 19 | import io.ballerina.runtime.api.Environment; 20 | import io.ballerina.runtime.api.utils.StringUtils; 21 | import io.ballerina.runtime.api.values.BString; 22 | import io.ballerina.runtime.observability.ObserveUtils; 23 | import io.ballerina.runtime.observability.ObserverContext; 24 | import io.ballerina.runtime.observability.metrics.Tag; 25 | 26 | public class GetTagValue { 27 | public static Object getTagValue(Environment env, BString tagKey) { 28 | if (ObserveUtils.isObservabilityEnabled()) { 29 | ObserverContext observerContext = ObserveUtils.getObserverContextOfCurrentFrame(env); 30 | if (observerContext == null) { 31 | return null; 32 | } 33 | Tag tag = observerContext.getTag(tagKey.getValue()); 34 | if (tag != null) { 35 | return StringUtils.fromString(tag.getValue()); 36 | } 37 | return null; 38 | } 39 | return null; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /ballerina-tests/src/test/resources/logging.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | # 4 | # WSO2 Inc. licenses this file to you under the Apache License, 5 | # Version 2.0 (the "License"); you may not use this file except 6 | # in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | # 18 | 19 | ####################### HANDLERS ####################### 20 | # Configurations for console logging 21 | java.util.logging.ConsoleHandler.level=ALL 22 | java.util.logging.ConsoleHandler.formatter=org.ballerinalang.logging.formatters.BallerinaLogFormatter 23 | org.ballerinalang.logging.formatters.BallerinaLogFormatter.format=%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS,%1$tL %2$s [%3$s] - %4$s %n 24 | 25 | org.ballerinalang.stdlib.common.TestLogHandler.level=INFO 26 | org.ballerinalang.stdlib.common.TestLogHandler.formatter=org.ballerinalang.logging.formatters.DefaultLogFormatter 27 | org.ballerinalang.logging.formatters.DefaultLogFormatter.format=[%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS,%1$tL] %2$s [%3$s] - %4$s %5$s %n 28 | 29 | ####################### LOGGERS ####################### 30 | # Ballerina user level root logger 31 | ballerina.handlers=java.util.logging.ConsoleHandler 32 | ballerina.level=SEVERE 33 | ballerina.useParentHandlers=false 34 | 35 | # JUL root logger 36 | .handlers=org.ballerinalang.stdlib.common.TestLogHandler 37 | .level=SEVERE 38 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/nativeimpl/GaugeRegister.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * WSO2 Inc. licenses this file to you under the Apache License, 4 | * Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, 11 | * software distributed under the License is distributed on an 12 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | * KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations 15 | * under the License. 16 | * 17 | */ 18 | package io.ballerina.stdlib.observe.nativeimpl; 19 | 20 | import io.ballerina.runtime.api.creators.ErrorCreator; 21 | import io.ballerina.runtime.api.utils.StringUtils; 22 | import io.ballerina.runtime.api.values.BObject; 23 | import io.ballerina.runtime.observability.metrics.Gauge; 24 | 25 | /** 26 | * This is the register function native implementation of the Gauge object. 27 | * 28 | * @since 0.980.0 29 | */ 30 | 31 | public class GaugeRegister { 32 | 33 | public static Object register(BObject guageObj) { 34 | try { 35 | Gauge gauge = (Gauge) guageObj.getNativeData(ObserveNativeImplConstants.METRIC_NATIVE_INSTANCE_KEY); 36 | Gauge registeredCounter = gauge.register(); 37 | guageObj.addNativeData(ObserveNativeImplConstants.METRIC_NATIVE_INSTANCE_KEY, registeredCounter); 38 | } catch (Exception e) { 39 | return ErrorCreator.createError(StringUtils.fromString((e.getMessage()))); 40 | } 41 | return null; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/nativeimpl/CounterRegister.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * WSO2 Inc. licenses this file to you under the Apache License, 4 | * Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, 11 | * software distributed under the License is distributed on an 12 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | * KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations 15 | * under the License. 16 | * 17 | */ 18 | package io.ballerina.stdlib.observe.nativeimpl; 19 | 20 | import io.ballerina.runtime.api.creators.ErrorCreator; 21 | import io.ballerina.runtime.api.utils.StringUtils; 22 | import io.ballerina.runtime.api.values.BObject; 23 | import io.ballerina.runtime.observability.metrics.Counter; 24 | 25 | /** 26 | * This is the native register function implementation of the Counter object. 27 | * 28 | * @since 0.980.0 29 | */ 30 | 31 | public class CounterRegister { 32 | 33 | public static Object register(BObject counterObj) { 34 | try { 35 | Counter counter = (Counter) counterObj.getNativeData(ObserveNativeImplConstants.METRIC_NATIVE_INSTANCE_KEY); 36 | Counter registeredCounter = counter.register(); 37 | counterObj.addNativeData(ObserveNativeImplConstants.METRIC_NATIVE_INSTANCE_KEY, registeredCounter); 38 | } catch (Exception e) { 39 | return ErrorCreator.createError(StringUtils.fromString((e.getMessage()))); 40 | } 41 | 42 | return null; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * This file was generated by the Gradle 'init' task. 3 | * 4 | * The settings file is used to specify which projects to include in your build. 5 | * 6 | * Detailed information about configuring a multi-project build in Gradle can be found 7 | * in the user manual at https://docs.gradle.org/7.2/userguide/multi_project_builds.html 8 | */ 9 | 10 | pluginManagement { 11 | plugins { 12 | id "com.github.spotbugs" version "${spotbugsPluginVersion}" 13 | id "com.github.johnrengelman.shadow" version "${shadowJarPluginVersion}" 14 | id "de.undercouch.download" version "${downloadPluginVersion}" 15 | id "net.researchgate.release" version "${releasePluginVersion}" 16 | id "io.ballerina.plugin" version "${ballerinaGradlePluginVersion}" 17 | } 18 | 19 | repositories { 20 | gradlePluginPortal() 21 | maven { 22 | url = 'https://maven.pkg.github.com/ballerina-platform/*' 23 | credentials { 24 | username System.getenv("packageUser") 25 | password System.getenv("packagePAT") 26 | } 27 | } 28 | } 29 | } 30 | 31 | plugins { 32 | id "com.gradle.enterprise" version "3.2" 33 | } 34 | 35 | rootProject.name = 'module-ballerina-observe' 36 | 37 | include ':checkstyle' 38 | include ':observe-native' 39 | include ':observe-ballerina' 40 | include ':observe-ballerina-tests' 41 | 42 | 43 | project(':checkstyle').projectDir = file("build-config${File.separator}checkstyle") 44 | project(':observe-native').projectDir = file('native') 45 | project(':observe-ballerina').projectDir = file('ballerina') 46 | project(':observe-ballerina-tests').projectDir = file('ballerina-tests') 47 | 48 | 49 | gradleEnterprise { 50 | buildScan { 51 | termsOfServiceUrl = 'https://gradle.com/terms-of-service' 52 | termsOfServiceAgree = 'yes' 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/mockextension/model/MockGauge.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.stdlib.observe.mockextension.model; 20 | 21 | import io.ballerina.runtime.observability.metrics.Snapshot; 22 | 23 | import java.util.Arrays; 24 | 25 | /** 26 | * Class for holding gauge related metrics data. 27 | */ 28 | public class MockGauge extends MockMetric { 29 | private double value; 30 | private long count; 31 | private double sum; 32 | private Snapshot[] snapshots; 33 | 34 | public double getValue() { 35 | return value; 36 | } 37 | 38 | public void setValue(double value) { 39 | this.value = value; 40 | } 41 | 42 | public long getCount() { 43 | return count; 44 | } 45 | 46 | public void setCount(long count) { 47 | this.count = count; 48 | } 49 | 50 | public double getSum() { 51 | return sum; 52 | } 53 | 54 | public void setSum(double sum) { 55 | this.sum = sum; 56 | } 57 | 58 | public Snapshot[] getSnapshots() { 59 | return snapshots == null ? new Snapshot[0] : Arrays.copyOf(snapshots, snapshots.length); 60 | } 61 | 62 | public void setSnapshots(Snapshot[] snapshots) { 63 | this.snapshots = Arrays.copyOf(snapshots, snapshots.length); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/nativeimpl/StartSpan.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | * 18 | */ 19 | 20 | package io.ballerina.stdlib.observe.nativeimpl; 21 | 22 | import io.ballerina.runtime.api.Environment; 23 | import io.ballerina.runtime.api.creators.ErrorCreator; 24 | import io.ballerina.runtime.api.utils.StringUtils; 25 | import io.ballerina.runtime.api.values.BMap; 26 | import io.ballerina.runtime.api.values.BString; 27 | 28 | /** 29 | * This function which implements the startSpan method for observe. 30 | */ 31 | 32 | public class StartSpan { 33 | public static Object startSpan(Environment env, BString spanName, Object tags, long parentSpanId) { 34 | if (parentSpanId < -1) { 35 | return ErrorCreator.createError( 36 | StringUtils.fromString(("The given parent span ID " + parentSpanId + " " + "is invalid."))); 37 | } else { 38 | long spanId = OpenTracerBallerinaWrapper.getInstance().startSpan( 39 | env, 40 | spanName.getValue(), 41 | Utils.toStringMap((BMap) tags), parentSpanId); 42 | if (spanId == -1) { 43 | return ErrorCreator.createError(StringUtils.fromString(( 44 | "No parent span for ID " + parentSpanId + " found. Please recheck the parent span Id"))); 45 | } 46 | 47 | return spanId; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /.github/workflows/daily-build.yml: -------------------------------------------------------------------------------- 1 | name: Daily build 2 | 3 | on: 4 | schedule: 5 | - cron: '30 18 * * *' 6 | workflow_dispatch: 7 | 8 | jobs: 9 | ubuntu-build: 10 | name: Build on Ubuntu 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout Repository 14 | uses: actions/checkout@v2 15 | - name: Set up JDK 21 16 | uses: actions/setup-java@v2 17 | with: 18 | distribution: 'temurin' 19 | java-version: 21 20 | - name: Build with Gradle 21 | env: 22 | packageUser: ${{ github.actor }} 23 | packagePAT: ${{ secrets.GITHUB_TOKEN }} 24 | run: | 25 | ./gradlew build test --stacktrace --console=plain 26 | - name: Generate Codecov Report 27 | uses: codecov/codecov-action@v3 28 | with: 29 | token: ${{ secrets.CODECOV_TOKEN }} 30 | 31 | windows-build: 32 | name: Build on Windows 33 | runs-on: windows-latest 34 | steps: 35 | - name: Checkout Repository 36 | uses: actions/checkout@v2 37 | - name: Set up JDK 21 38 | uses: actions/setup-java@v2 39 | with: 40 | distribution: 'temurin' 41 | java-version: 21 42 | - name: Build with Gradle 43 | env: 44 | packageUser: ${{ github.actor }} 45 | packagePAT: ${{ secrets.GITHUB_TOKEN }} 46 | JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8 47 | run: | 48 | ./gradlew.bat build -x test --stacktrace --console=plain 49 | ./gradlew.bat test --stacktrace --console=plain 50 | 51 | ubuntu-build-without-native-tests: 52 | name: Build on Ubuntu without native tests 53 | runs-on: ubuntu-latest 54 | steps: 55 | - name: Checkout Repository 56 | uses: actions/checkout@v2 57 | - name: Set up JDK 21 58 | uses: actions/setup-java@v2 59 | with: 60 | distribution: 'temurin' 61 | java-version: 21 62 | - name: Build with Gradle 63 | env: 64 | packageUser: ${{ github.actor }} 65 | packagePAT: ${{ secrets.GITHUB_TOKEN }} 66 | run: ./gradlew build -x observe-ballerina-tests:test --stacktrace --console=plain 67 | -------------------------------------------------------------------------------- /.github/workflows/pull-request.yml: -------------------------------------------------------------------------------- 1 | name: Ballerina Observe module build 2 | 3 | on: [pull_request] 4 | 5 | jobs: 6 | ubuntu-build: 7 | name: Build on Ubuntu 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout Repository 11 | uses: actions/checkout@v2 12 | - name: Set up JDK 21 13 | uses: actions/setup-java@v2 14 | with: 15 | distribution: 'adopt' 16 | java-version: 21 17 | - name: Build with Gradle 18 | env: 19 | packageUser: ${{ github.actor }} 20 | packagePAT: ${{ secrets.GITHUB_TOKEN }} 21 | run: | 22 | ./gradlew build test --stacktrace --console=plain 23 | - name: Generate Codecov Report 24 | uses: codecov/codecov-action@v3 25 | with: 26 | token: ${{ secrets.CODECOV_TOKEN }} 27 | 28 | windows-build: 29 | name: Build on Windows 30 | runs-on: windows-latest 31 | steps: 32 | - name: Checkout Repository 33 | uses: actions/checkout@v2 34 | - name: Set up JDK 21 35 | uses: actions/setup-java@v2 36 | with: 37 | distribution: 'temurin' 38 | java-version: 21 39 | - name: Build with Gradle 40 | env: 41 | packageUser: ${{ github.actor }} 42 | packagePAT: ${{ secrets.GITHUB_TOKEN }} 43 | JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8 44 | run: | 45 | ./gradlew.bat build -x test --stacktrace --console=plain 46 | ./gradlew.bat test --stacktrace --console=plain 47 | 48 | ubuntu-build-without-native-tests: 49 | name: Build on Ubuntu without native tests 50 | runs-on: ubuntu-latest 51 | steps: 52 | - name: Checkout Repository 53 | uses: actions/checkout@v2 54 | - name: Set up JDK 21 55 | uses: actions/setup-java@v2 56 | with: 57 | distribution: 'adopt' 58 | java-version: 21 59 | - name: Build with Gradle 60 | env: 61 | packageUser: ${{ github.actor }} 62 | packagePAT: ${{ secrets.GITHUB_TOKEN }} 63 | run: ./gradlew build -x observe-ballerina-tests:test --stacktrace --console=plain 64 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/nativeimpl/AddTagToMetrics.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | * 18 | */ 19 | 20 | package io.ballerina.stdlib.observe.nativeimpl; 21 | 22 | import io.ballerina.runtime.api.Environment; 23 | import io.ballerina.runtime.api.values.BString; 24 | import io.ballerina.runtime.observability.ObserveUtils; 25 | import io.ballerina.runtime.observability.ObserverContext; 26 | import io.ballerina.runtime.observability.metrics.Tag; 27 | 28 | import java.util.HashMap; 29 | 30 | /** 31 | * This function add tags to System Metrics. 32 | * Custom tag is not included in the 'in progress-requests' 33 | */ 34 | public class AddTagToMetrics { 35 | 36 | public static Object addTagToMetrics(Environment env, BString tagKey, BString tagValue) { 37 | 38 | if (!ObserveUtils.isMetricsEnabled()) { 39 | return null; 40 | } 41 | 42 | ObserverContext observerContext = ObserveUtils.getObserverContextOfCurrentFrame(env); 43 | if (observerContext != null) { 44 | 45 | if (observerContext.customMetricTags == null) { 46 | observerContext.customMetricTags = new HashMap<>(); 47 | } 48 | observerContext.customMetricTags.put(tagKey.getValue(), Tag.of(tagKey.getValue(), tagValue.getValue())); 49 | return null; 50 | } 51 | // ObserverContext will be null if function is executed without entry point like main or resource 52 | // function ex. initialising phase. 53 | return null; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/nativeimpl/FinishSpan.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | * 18 | */ 19 | 20 | package io.ballerina.stdlib.observe.nativeimpl; 21 | 22 | import io.ballerina.runtime.api.Environment; 23 | import io.ballerina.runtime.api.creators.ErrorCreator; 24 | import io.ballerina.runtime.api.utils.StringUtils; 25 | import io.ballerina.runtime.api.values.BError; 26 | 27 | /** 28 | * This function which implements the finishSpan method for observe. 29 | */ 30 | 31 | public class FinishSpan { 32 | private static final OpenTracerBallerinaWrapper otWrapperInstance = OpenTracerBallerinaWrapper.getInstance(); 33 | 34 | public static Object finishSpan(Environment env, long spanId) { 35 | boolean isFinished = OpenTracerBallerinaWrapper.getInstance().finishSpan(env, spanId); 36 | 37 | if (isFinished) { 38 | return null; 39 | } 40 | 41 | return ErrorCreator.createError(StringUtils.fromString(("Can not finish span with id " + spanId + ". Span " + 42 | "already finished"))); 43 | } 44 | 45 | public static Object finishSpanWithError(Environment env, long spanId, BError error) { 46 | boolean isFinished = OpenTracerBallerinaWrapper.getInstance().finishSpanWithError(env, spanId, 47 | error); 48 | 49 | if (isFinished) { 50 | return null; 51 | } 52 | 53 | return ErrorCreator.createError(StringUtils.fromString(("Can not finish span with id " + spanId + ". Span " + 54 | "already finished"))); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/nativeimpl/GetSpanContext.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * WSO2 Inc. licenses this file to you under the Apache License, 4 | * Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, 11 | * software distributed under the License is distributed on an 12 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | * KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations 15 | * under the License. 16 | * 17 | */ 18 | 19 | package io.ballerina.stdlib.observe.nativeimpl; 20 | 21 | import io.ballerina.runtime.api.Environment; 22 | import io.ballerina.runtime.api.creators.TypeCreator; 23 | import io.ballerina.runtime.api.creators.ValueCreator; 24 | import io.ballerina.runtime.api.types.PredefinedTypes; 25 | import io.ballerina.runtime.api.values.BMap; 26 | import io.ballerina.runtime.api.values.BString; 27 | import io.ballerina.runtime.observability.ObserveUtils; 28 | import io.ballerina.runtime.observability.ObserverContext; 29 | import io.ballerina.runtime.observability.tracer.BSpan; 30 | 31 | /** 32 | * This implements the getSpanContext function for observe. 33 | * The map returned by the method contains traceId and spanId if the request was sampled. 34 | * 35 | * @since 2.0.0 36 | */ 37 | 38 | public class GetSpanContext { 39 | 40 | private static final BMap EMPTY_BSPAN_CONTEXT = ValueCreator.createMapValue( 41 | TypeCreator.createMapType(PredefinedTypes.TYPE_STRING, true)); 42 | 43 | public static BMap getSpanContext(Environment env) { 44 | 45 | ObserverContext observerContext = ObserveUtils.getObserverContextOfCurrentFrame(env); 46 | if (observerContext != null) { 47 | BSpan bSpan = observerContext.getSpan(); 48 | if (bSpan != null) { 49 | return bSpan.getBSpanContext(); 50 | } 51 | } 52 | return EMPTY_BSPAN_CONTEXT; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/mockextension/MockTracerUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | * 18 | */ 19 | 20 | package io.ballerina.stdlib.observe.mockextension; 21 | 22 | import com.google.gson.Gson; 23 | import io.ballerina.runtime.api.utils.JsonUtils; 24 | import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; 25 | import io.opentelemetry.sdk.trace.data.SpanData; 26 | 27 | import java.util.Collections; 28 | import java.util.List; 29 | import java.util.stream.Collectors; 30 | 31 | /** 32 | * Java functions called from Ballerina related to the mock tracer. 33 | */ 34 | public class MockTracerUtils { 35 | public static Object getFinishedSpans(String serviceName) { 36 | InMemorySpanExporter spanExporter = BMockTracerProvider.getExporterMap().get(serviceName); 37 | 38 | List mockSpans; 39 | if (spanExporter == null) { 40 | mockSpans = Collections.emptyList(); 41 | } else { 42 | List finishedSpanList = spanExporter.getFinishedSpanItems(); 43 | mockSpans = finishedSpanList.stream() 44 | .map(spanData -> new BMockSpan(spanData.getName(), 45 | spanData.getTraceId(), 46 | spanData.getSpanId(), 47 | spanData.getParentSpanId(), 48 | spanData.getAttributes(), 49 | spanData.getEvents())) 50 | .collect(Collectors.toList()); 51 | } 52 | return JsonUtils.parse(new Gson().toJson(mockSpans)); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/nativeimpl/ObserveNativeImplConstants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | package io.ballerina.stdlib.observe.nativeimpl; 19 | 20 | import io.ballerina.runtime.api.utils.StringUtils; 21 | import io.ballerina.runtime.api.values.BString; 22 | 23 | /** 24 | * Constants used in Ballerina Observe package. 25 | * 26 | * @since 0.980.0 27 | */ 28 | public final class ObserveNativeImplConstants { 29 | 30 | private ObserveNativeImplConstants() { 31 | } 32 | 33 | public static final String GAUGE = "Gauge"; 34 | public static final String COUNTER = "Counter"; 35 | public static final String SNAPSHOT = "Snapshot"; 36 | public static final String METRIC = "Metric"; 37 | public static final String STATISTIC_CONFIG = "StatisticConfig"; 38 | public static final String PERCENTILE_VALUE = "PercentileValue"; 39 | public static final String METRIC_NATIVE_INSTANCE_KEY = "__metric_native_instance__"; 40 | 41 | public static final BString NAME_FIELD = StringUtils.fromString("name"); 42 | public static final BString DESCRIPTION_FIELD = StringUtils.fromString("description"); 43 | public static final BString TAGS_FIELD = StringUtils.fromString("metricTags"); 44 | public static final BString STATISTICS_CONFIG_FIELD = StringUtils.fromString("statisticConfigs"); 45 | public static final BString EXPIRY_FIELD = StringUtils.fromString("timeWindow"); 46 | public static final BString BUCKETS_FIELD = StringUtils.fromString("buckets"); 47 | public static final BString PERCENTILES_FIELD = StringUtils.fromString("percentiles"); 48 | } 49 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/mockextension/model/Metrics.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.stdlib.observe.mockextension.model; 20 | 21 | import java.util.ArrayList; 22 | import java.util.List; 23 | 24 | /** 25 | * Class for holding all the metrics types. 26 | */ 27 | public class Metrics { 28 | List counters; 29 | List gauges; 30 | List polledGauges; 31 | 32 | public Metrics() { 33 | counters = new ArrayList<>(); 34 | gauges = new ArrayList<>(); 35 | polledGauges = new ArrayList<>(); 36 | } 37 | 38 | public List getCounters() { 39 | return counters; 40 | } 41 | 42 | public void addCounter(MockCounter counter) { 43 | this.counters.add(counter); 44 | } 45 | 46 | public void addAllCounters(List counters) { 47 | this.counters.addAll(counters); 48 | } 49 | 50 | public List getGauges() { 51 | return gauges; 52 | } 53 | 54 | public void addGauge(MockGauge gauge) { 55 | this.gauges.add(gauge); 56 | } 57 | 58 | public void addAllGauges(List gauges) { 59 | this.gauges.addAll(gauges); 60 | } 61 | 62 | public List getPolledGauges() { 63 | return polledGauges; 64 | } 65 | 66 | public void addPolledGauge(MockPolledGauge polledGauge) { 67 | this.polledGauges.add(polledGauge); 68 | } 69 | 70 | public void addAllPolledGauges(List polledGauges) { 71 | this.polledGauges.addAll(polledGauges); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /ballerina-tests/src/test/resources/test-src/counter_test.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/observe; 18 | 19 | function testCounterIncrementByOne() returns (int) { 20 | map tags = { "method": "GET" }; 21 | observe:Counter counter = new("RequestCounter", tags = tags); 22 | counter.increment(1); 23 | return counter.getValue(); 24 | } 25 | 26 | function testCounterIncrement() returns (int) { 27 | observe:Counter counter = new("RequestCounter"); 28 | counter.increment(5); 29 | return counter.getValue(); 30 | } 31 | 32 | function testCounterError() returns (float) { 33 | map tags = { "method": "PUT" }; 34 | observe:Counter counter1 = new("requests_total", "Total requests.", tags); 35 | checkpanic counter1.register(); 36 | counter1.increment(5); 37 | observe:Gauge gauge = new("requests_total", "Total requests.", tags); 38 | error? err = gauge.register(); 39 | if err is error { 40 | panic err; 41 | } else { 42 | gauge.increment(5.0); 43 | return gauge.getValue(); 44 | } 45 | } 46 | 47 | function testCounterWithoutTags() returns (int) { 48 | observe:Counter counter1 = new("new_requests_total"); 49 | counter1.increment(2); 50 | counter1.increment(1); 51 | return counter1.getValue(); 52 | } 53 | 54 | function testReset() returns (boolean) { 55 | map tags = { "method": "PUT" }; 56 | observe:Counter counter1 = new("requests_total", "Total requests.", tags); 57 | checkpanic counter1.register(); 58 | int value = counter1.getValue(); 59 | counter1.reset(); 60 | int newValue = counter1.getValue(); 61 | return (value != newValue && newValue == 0); 62 | } 63 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/mockextension/typeadapter/DurationTypeAdapter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com) All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.stdlib.observe.mockextension.typeadapter; 20 | 21 | import com.google.gson.Gson; 22 | import com.google.gson.JsonDeserializationContext; 23 | import com.google.gson.JsonDeserializer; 24 | import com.google.gson.JsonElement; 25 | import com.google.gson.JsonParseException; 26 | import com.google.gson.JsonSerializationContext; 27 | import com.google.gson.JsonSerializer; 28 | 29 | import java.lang.reflect.Type; 30 | import java.time.Duration; 31 | 32 | /** 33 | * Provides a custom serializer and deserializer to convert {@link Duration} to and from JSON. 34 | * 35 | * @since 1.2.0 36 | */ 37 | public class DurationTypeAdapter implements JsonSerializer, JsonDeserializer { 38 | 39 | private static final Gson gson = new Gson(); 40 | 41 | @Override 42 | public JsonElement serialize(final Duration duration, final Type typeOfSrc, 43 | final JsonSerializationContext context) { 44 | long seconds = duration.getSeconds(); 45 | int nanos = duration.getNano(); 46 | DurationData durationData = new DurationData(seconds, nanos); 47 | return gson.toJsonTree(durationData); 48 | } 49 | 50 | @Override 51 | public Duration deserialize(final JsonElement json, final Type typeOfT, 52 | final JsonDeserializationContext context) throws JsonParseException { 53 | DurationData data = gson.fromJson(json, DurationData.class); 54 | return Duration.ofSeconds(data.seconds(), data.nanos()); 55 | } 56 | 57 | private record DurationData(long seconds, int nanos) { } 58 | } 59 | -------------------------------------------------------------------------------- /ballerina/modules/mockextension/tracing.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/jballerina.java; 18 | 19 | # Holds the event data. 20 | # + name - Name of the event 21 | # + timestampMicros - Timestamp value in microseconds 22 | # + tags - Tags associated with the event 23 | public type Event record { 24 | string name; 25 | int timestampMicros; 26 | map tags; 27 | }; 28 | 29 | # Holds the span data. 30 | # + operationName - Name of the operation 31 | # + traceId - Id for trace 32 | # + spanId - Id for span 33 | # + parentId - Id for parent span 34 | # + tags - Tags associated with the event 35 | # + events - Event details 36 | public type Span record { 37 | string operationName; 38 | string traceId; 39 | string spanId; 40 | string parentId; 41 | map tags; 42 | Event[] events; 43 | }; 44 | 45 | # Get all the finished spans. 46 | # 47 | # + serviceName - The name of the service of which the finished spans should be fetched 48 | # + return - The finished spans 49 | public isolated function getFinishedSpans(string serviceName) returns Span[] { 50 | handle serviceNameHandle = java:fromString(serviceName); 51 | json spansJson = externGetFinishedSpans(serviceNameHandle); 52 | Span[] | error spans = spansJson.cloneWithType(); 53 | if (spans is error) { 54 | panic error("cannot convert to Span record array; json string: " + spansJson.toJsonString(), spans); 55 | } else { 56 | return spans; 57 | } 58 | } 59 | 60 | # Get all the finished spans. 61 | # 62 | # + serviceName - The name of the service of which the finished spans should be fetched 63 | # + return - The finished spans as a json 64 | isolated function externGetFinishedSpans(handle serviceName) returns json = @java:Method { 65 | name: "getFinishedSpans", 66 | 'class: "io.ballerina.stdlib.observe.mockextension.MockTracerUtils" 67 | } external; 68 | -------------------------------------------------------------------------------- /ballerina-tests/src/test/resources/test-src/metrics_registry_test.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/observe; 18 | 19 | function getAllMetricsSize() returns (int) { 20 | observe:Metric?[] metrics = observe:getAllMetrics(); 21 | return (metrics.length()); 22 | } 23 | 24 | function registerAngGetMetrics() returns (int) { 25 | map tags = { "method": "PUT" }; 26 | observe:Counter counter1 = new("service_requests_total", "Total requests.", tags); 27 | checkpanic counter1.register(); 28 | counter1.increment(5); 29 | return getAllMetricsSize(); 30 | } 31 | 32 | function lookupRegisteredMetrics() returns (boolean) { 33 | string name = "service_requests_total"; 34 | map tags = { "method": "PUT" }; 35 | observe:Counter|observe:Gauge|() metric = observe:lookupMetric(name, tags); 36 | 37 | if metric is observe:Counter { 38 | int value = metric.getValue(); 39 | return (value == 5); 40 | } 41 | 42 | return false; 43 | } 44 | 45 | function lookupRegisteredNameOnlyMetrics() returns (boolean) { 46 | string name = "service_requests_total"; 47 | observe:Counter|observe:Gauge|() metric = observe:lookupMetric(name); 48 | if metric is observe:Counter { 49 | return true; 50 | } 51 | 52 | if metric is observe:Gauge { 53 | return true; 54 | } 55 | 56 | return false; 57 | } 58 | 59 | function lookupRegisterAndIncrement() returns (boolean) { 60 | string name = "service_requests_total"; 61 | map tags = { "method": "PUT" }; 62 | observe:Counter|observe:Gauge|() metric = observe:lookupMetric(name, tags); 63 | if metric is observe:Counter { 64 | metric.increment(10); 65 | observe:Counter|observe:Gauge|() nextLookupMetric = observe:lookupMetric(name, tags); 66 | if nextLookupMetric is observe:Counter { 67 | return (nextLookupMetric.getValue() == 15); 68 | } 69 | return false; 70 | } 71 | return false; 72 | } 73 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/mockextension/BMockTracerProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.stdlib.observe.mockextension; 20 | 21 | import io.ballerina.runtime.observability.tracer.spi.TracerProvider; 22 | import io.opentelemetry.api.trace.Tracer; 23 | import io.opentelemetry.context.propagation.ContextPropagators; 24 | import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; 25 | import io.opentelemetry.sdk.trace.SdkTracerProvider; 26 | import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; 27 | 28 | import java.io.PrintStream; 29 | import java.util.Collections; 30 | import java.util.Map; 31 | import java.util.concurrent.ConcurrentHashMap; 32 | 33 | /** 34 | * Tracer provider factory which returns mock tracer provider instance. 35 | */ 36 | public class BMockTracerProvider implements TracerProvider { 37 | private static final PrintStream out = System.out; 38 | private static final Map exporterMap = new ConcurrentHashMap<>(); 39 | 40 | @Override 41 | public String getName() { 42 | return "mock"; 43 | } 44 | 45 | @Override 46 | public void init() { // Do Nothing 47 | } 48 | 49 | public static Map getExporterMap() { 50 | return Collections.unmodifiableMap(exporterMap); 51 | } 52 | 53 | @Override 54 | public Tracer getTracer(String serviceName) { 55 | InMemorySpanExporter inMemorySpanExporter = InMemorySpanExporter.create(); 56 | exporterMap.put(serviceName, inMemorySpanExporter); 57 | out.println("Initialized Mock Tracer for " + serviceName); 58 | SdkTracerProvider tracerProvider = SdkTracerProvider.builder() 59 | .addSpanProcessor(SimpleSpanProcessor.create(inMemorySpanExporter)) 60 | .build(); 61 | return tracerProvider.get(serviceName); 62 | } 63 | 64 | @Override 65 | public ContextPropagators getPropagators() { 66 | return ContextPropagators.noop(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Purpose 2 | > Describe the problems, issues, or needs driving this feature/fix and include links to related issues in the following format: Resolves issue1, issue2, etc. 3 | 4 | ## Goals 5 | > Describe the solutions that this feature/fix will introduce to resolve the problems described above 6 | 7 | ## Approach 8 | > Describe how you are implementing the solutions. Include an animated GIF or screenshot if the change affects the UI (email documentation@wso2.com to review all UI text). Include a link to a Markdown file or Google doc if the feature write-up is too long to paste here. 9 | 10 | ## User stories 11 | > Summary of user stories addressed by this change> 12 | 13 | ## Release note 14 | > Brief description of the new feature or bug fix as it will appear in the release notes 15 | 16 | ## Documentation 17 | > Link(s) to product documentation that addresses the changes of this PR. If no doc impact, enter “N/A” plus brief explanation of why there’s no doc impact 18 | 19 | ## Training 20 | > Link to the PR for changes to the training content in https://github.com/wso2/WSO2-Training, if applicable 21 | 22 | ## Certification 23 | > Type “Sent” when you have provided new/updated certification questions, plus four answers for each question (correct answer highlighted in bold), based on this change. Certification questions/answers should be sent to certification@wso2.com and NOT pasted in this PR. If there is no impact on certification exams, type “N/A” and explain why. 24 | 25 | ## Marketing 26 | > Link to drafts of marketing content that will describe and promote this feature, including product page changes, technical articles, blog posts, videos, etc., if applicable 27 | 28 | ## Automation tests 29 | - Unit tests 30 | > Code coverage information 31 | - Integration tests 32 | > Details about the test cases and coverage 33 | 34 | ## Security checks 35 | - Followed secure coding standards in http://wso2.com/technical-reports/wso2-secure-engineering-guidelines? yes/no 36 | - Ran FindSecurityBugs plugin and verified report? yes/no 37 | - Confirmed that this PR doesn't commit any keys, passwords, tokens, usernames, or other secrets? yes/no 38 | 39 | ## Samples 40 | > Provide high-level details about the samples related to this feature 41 | 42 | ## Related PRs 43 | > List any other related PRs 44 | 45 | ## Migrations (if applicable) 46 | > Describe migration steps and platforms on which migration has been tested 47 | 48 | ## Test environment 49 | > List all JDK versions, operating systems, databases, and browser/versions on which this feature/fix was tested 50 | 51 | ## Learning 52 | > Describe the research phase and any blog posts, patterns, libraries, or add-ons you used to solve the problem. -------------------------------------------------------------------------------- /ballerina-tests/src/test/java/io/ballerina/stdlib/observe/CounterTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | package io.ballerina.stdlib.observe; 19 | 20 | import org.ballerinalang.test.BCompileUtil; 21 | import org.ballerinalang.test.BRunUtil; 22 | import org.ballerinalang.test.CompileResult; 23 | import org.testng.Assert; 24 | import org.testng.annotations.BeforeClass; 25 | import org.testng.annotations.Test; 26 | 27 | import java.nio.file.Path; 28 | import java.nio.file.Paths; 29 | 30 | /** 31 | * Tests for Counter metric. 32 | * 33 | * @since 0.980.0 34 | */ 35 | public class CounterTest extends MetricTest { 36 | private CompileResult compileResult; 37 | 38 | @BeforeClass 39 | public void setup() { 40 | String resourceRoot = Paths.get("src", "test", "resources").toAbsolutePath().toString(); 41 | Path testResourceRoot = Paths.get(resourceRoot, "test-src"); 42 | compileResult = BCompileUtil.compile(testResourceRoot.resolve("counter_test.bal").toString()); 43 | } 44 | 45 | @Test 46 | public void testCounterIncrementByOne() { 47 | Object returns = BRunUtil.invoke(compileResult, "testCounterIncrementByOne"); 48 | Assert.assertEquals(returns, 1L); 49 | } 50 | 51 | @Test 52 | public void testCounterIncrement() { 53 | Object returns = BRunUtil.invoke(compileResult, "testCounterIncrement"); 54 | Assert.assertEquals(returns, 5L); 55 | } 56 | 57 | @Test(dependsOnGroups = "RegistryTest.testRegister") 58 | public void testCounterError() { 59 | try { 60 | BRunUtil.invoke(compileResult, "testCounterError"); 61 | Assert.fail("Should not be registered again"); 62 | } catch (RuntimeException e) { 63 | Assert.assertTrue(e.getMessage().contains("is already used for a different type of metric"), 64 | "Unexpected Ballerina Error"); 65 | } 66 | } 67 | 68 | @Test 69 | public void testCounterWithoutTags() { 70 | Object returns = BRunUtil.invoke(compileResult, "testCounterWithoutTags"); 71 | Assert.assertEquals(returns, 3L); 72 | } 73 | 74 | @Test(dependsOnGroups = "RegistryTest.testRegister") 75 | public void testReset() { 76 | Object returns = BRunUtil.invoke(compileResult, "testReset"); 77 | Assert.assertTrue((Boolean) returns); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /ballerina-tests/src/test/java/io/ballerina/stdlib/observe/SummaryTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | package io.ballerina.stdlib.observe; 19 | 20 | import org.ballerinalang.test.BCompileUtil; 21 | import org.ballerinalang.test.BRunUtil; 22 | import org.ballerinalang.test.CompileResult; 23 | import org.testng.Assert; 24 | import org.testng.annotations.BeforeClass; 25 | import org.testng.annotations.Test; 26 | 27 | import java.nio.file.Path; 28 | import java.nio.file.Paths; 29 | import java.text.DecimalFormat; 30 | 31 | /** 32 | * Tests for summary metric. 33 | * 34 | * @since 0.980.0 35 | */ 36 | public class SummaryTest extends MetricTest { 37 | private CompileResult compileResult; 38 | private DecimalFormat df = new DecimalFormat("#.#"); 39 | 40 | 41 | @BeforeClass 42 | public void setup() { 43 | String resourceRoot = Paths.get("src", "test", "resources").toAbsolutePath().toString(); 44 | Path testResourceRoot = Paths.get(resourceRoot, "test-src"); 45 | compileResult = BCompileUtil.compile(testResourceRoot.resolve("summary_test.bal").toString()); 46 | } 47 | 48 | @Test 49 | public void testMaxSummary() { 50 | Object returns = BRunUtil.invoke(compileResult, "testMaxSummary"); 51 | Assert.assertEquals(round((Double) returns), 3.0); 52 | } 53 | 54 | @Test 55 | public void testMeanSummary() { 56 | Object returns = BRunUtil.invoke(compileResult, "testMeanSummary"); 57 | Assert.assertEquals(round((Double) returns), 2.0); 58 | } 59 | 60 | @Test 61 | public void testValueSummary() { 62 | Object returns = BRunUtil.invoke(compileResult, "testValueSummary"); 63 | Assert.assertEquals(round((Double) returns), 500.0); 64 | } 65 | 66 | @Test 67 | public void testSummaryWithoutTags() { 68 | Object returns = BRunUtil.invoke(compileResult, "testSummaryWithoutTags"); 69 | Assert.assertEquals(round((Double) returns), 2.0); 70 | } 71 | 72 | @Test(groups = "SummaryTest.testRegisteredGauge") 73 | public void testRegisteredGauge() { 74 | Object returns = null; 75 | for (int i = 0; i < 3; i++) { 76 | returns = BRunUtil.invoke(compileResult, "registerAndIncrement"); 77 | } 78 | Assert.assertEquals(round((Double) returns), 3.0); 79 | } 80 | 81 | private double round(double value) { 82 | return Double.parseDouble(df.format(value)); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /.github/workflows/publish-release.yml: -------------------------------------------------------------------------------- 1 | name: Publish release 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | publish-release: 8 | runs-on: ubuntu-latest 9 | if: github.repository_owner == 'ballerina-platform' 10 | 11 | steps: 12 | - name: Checkout Repository 13 | uses: actions/checkout@v2 14 | - name: Set up JDK 21 15 | uses: actions/setup-java@v2 16 | with: 17 | distribution: 'adopt' 18 | java-version: 21 19 | - name: Build with Gradle 20 | env: 21 | packageUser: ${{ github.actor }} 22 | packagePAT: ${{ secrets.GITHUB_TOKEN }} 23 | run: ./gradlew build -x check -x test --stacktrace --console=plain 24 | - name: Run Trivy vulnerability scanner 25 | uses: aquasecurity/trivy-action@master 26 | with: 27 | scan-type: 'fs' 28 | scan-ref: "${{ github.workspace }}/ballerina/lib" 29 | format: 'table' 30 | timeout: '6m0s' 31 | exit-code: '1' 32 | - name: Set version env variable 33 | run: echo "VERSION=$((grep -w 'version' | cut -d= -f2) < gradle.properties | rev | cut --complement -d- -f1 | rev)" >> $GITHUB_ENV 34 | - name: Pre release depenency version update 35 | env: 36 | GITHUB_TOKEN: ${{ secrets.BALLERINA_BOT_TOKEN }} 37 | run: | 38 | echo "Version: ${VERSION}" 39 | git config user.name ${{ secrets.BALLERINA_BOT_USERNAME }} 40 | git config user.email ${{ secrets.BALLERINA_BOT_EMAIL }} 41 | git checkout -b release-${VERSION} 42 | sed -i 's/ballerinaLangVersion=\(.*\)-SNAPSHOT/ballerinaLangVersion=\1/g' gradle.properties 43 | sed -i 's/ballerinaLangVersion=\(.*\)-[0-9]\{8\}-[0-9]\{6\}-.*$/ballerinaLangVersion=\1/g' gradle.properties 44 | sed -i 's/stdlib\(.*\)=\(.*\)-SNAPSHOT/stdlib\1=\2/g' gradle.properties 45 | sed -i 's/stdlib\(.*\)=\(.*\)-[0-9]\{8\}-[0-9]\{6\}-.*$/stdlib\1=\2/g' gradle.properties 46 | git add gradle.properties 47 | git commit -m "Move dependencies to stable version" || echo "No changes to commit" 48 | - name: Publish artifact 49 | env: 50 | GITHUB_TOKEN: ${{ secrets.BALLERINA_BOT_TOKEN }} 51 | BALLERINA_CENTRAL_ACCESS_TOKEN: ${{ secrets.BALLERINA_CENTRAL_ACCESS_TOKEN }} 52 | packageUser: ${{ secrets.BALLERINA_BOT_USERNAME }} 53 | packagePAT: ${{ secrets.BALLERINA_BOT_TOKEN }} 54 | publishUser: ${{ secrets.BALLERINA_BOT_USERNAME }} 55 | publishPAT: ${{ secrets.BALLERINA_BOT_TOKEN }} 56 | run: | 57 | rm -rf .cache 58 | rm -rf trivy 59 | git stash 60 | ./gradlew clean release -Prelease.useAutomaticVersion=true --stacktrace --console=plain 61 | ./gradlew -Pversion=${VERSION} publish -x test -PpublishToCentral=true --stacktrace --console=plain 62 | - name: GitHub Release and Release Sync PR 63 | env: 64 | GITHUB_TOKEN: ${{ secrets.BALLERINA_BOT_TOKEN }} 65 | run: | 66 | gh release create v$VERSION --title "module-ballerina-observe-v$VERSION" 67 | gh pr create --title "[Automated] Sync master after $VERSION release" --body "Sync master after $VERSION release" 68 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/nativeimpl/GaugeInitialize.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * WSO2 Inc. licenses this file to you under the Apache License, 4 | * Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, 11 | * software distributed under the License is distributed on an 12 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | * KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations 15 | * under the License. 16 | * 17 | */ 18 | package io.ballerina.stdlib.observe.nativeimpl; 19 | 20 | import io.ballerina.runtime.api.values.BArray; 21 | import io.ballerina.runtime.api.values.BMap; 22 | import io.ballerina.runtime.api.values.BObject; 23 | import io.ballerina.runtime.api.values.BString; 24 | import io.ballerina.runtime.observability.metrics.Gauge; 25 | import io.ballerina.runtime.observability.metrics.StatisticConfig; 26 | 27 | import java.time.Duration; 28 | 29 | /** 30 | * This is the native initialize function that's getting called when instantiating the Gauge object. 31 | * 32 | * @since 0.980.0 33 | */ 34 | 35 | public class GaugeInitialize { 36 | 37 | public static void initialize(BObject guage) { 38 | BArray summaryConfigs = (BArray) guage.get(ObserveNativeImplConstants.STATISTICS_CONFIG_FIELD); 39 | Gauge.Builder gaugeBuilder = Gauge.builder(guage.get(ObserveNativeImplConstants.NAME_FIELD).toString()) 40 | .description(guage.get(ObserveNativeImplConstants.DESCRIPTION_FIELD).toString()) 41 | .tags(Utils.toStringMap((BMap) guage.get(ObserveNativeImplConstants.TAGS_FIELD))); 42 | if (summaryConfigs != null && summaryConfigs.size() > 0) { 43 | for (int i = 0; i < summaryConfigs.size(); i++) { 44 | BMap summaryConfigStruct = (BMap) summaryConfigs.get(i); 45 | StatisticConfig.Builder statisticBuilder = StatisticConfig.builder().expiry( 46 | Duration.ofMillis(((long) summaryConfigStruct.get(ObserveNativeImplConstants.EXPIRY_FIELD)))) 47 | .buckets(((long) summaryConfigStruct.get(ObserveNativeImplConstants.BUCKETS_FIELD))); 48 | BArray bFloatArray = 49 | (BArray) summaryConfigStruct.get(ObserveNativeImplConstants.PERCENTILES_FIELD); 50 | double[] percentiles = new double[(int) bFloatArray.size()]; 51 | for (int j = 0; j < bFloatArray.size(); j++) { 52 | percentiles[j] = bFloatArray.getFloat(j); 53 | } 54 | statisticBuilder.percentiles(percentiles); 55 | StatisticConfig config = statisticBuilder.build(); 56 | gaugeBuilder.summarize(config); 57 | } 58 | } 59 | Gauge gauge = gaugeBuilder.build(); 60 | guage.addNativeData(ObserveNativeImplConstants.METRIC_NATIVE_INSTANCE_KEY, gauge); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /ballerina-tests/src/test/resources/test-src/summary_test.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/observe; 18 | 19 | function testMaxSummary() returns (float) { 20 | map tags = { "method": "POST" }; 21 | observe:Gauge gauge = new("response_size", "Size of a response.", tags); 22 | gauge.setValue(1.0); 23 | gauge.setValue(2.0); 24 | gauge.setValue(3.0); 25 | observe:Snapshot[]? summarySnapshot = gauge.getSnapshot(); 26 | if summarySnapshot is observe:Snapshot[] { 27 | return summarySnapshot[0].max; 28 | } else { 29 | return 0.0; 30 | } 31 | } 32 | 33 | function testMeanSummary() returns (float) { 34 | map tags = { "method": "UPDATE" }; 35 | observe:Gauge gauge = new("response_size", "Size of a response.", tags); 36 | gauge.setValue(1.0); 37 | gauge.setValue(2.0); 38 | gauge.setValue(3.0); 39 | observe:Snapshot[]? summarySnapshot = gauge.getSnapshot(); 40 | if summarySnapshot is observe:Snapshot[] { 41 | return summarySnapshot[0].mean; 42 | } else { 43 | return 0.0; 44 | } 45 | } 46 | 47 | function testPercentileSummary() returns (observe:PercentileValue[]?) { 48 | map tags = { "method": "DELETE" }; 49 | observe:Gauge gauge = new("response_size", "Size of a response.", tags); 50 | gauge.setValue(1.0); 51 | gauge.setValue(2.0); 52 | gauge.setValue(3.0); 53 | gauge.setValue(4.0); 54 | gauge.setValue(5.0); 55 | gauge.setValue(6.0); 56 | observe:Snapshot[]? summarySnapshot = gauge.getSnapshot(); 57 | if summarySnapshot is observe:Snapshot[] { 58 | return summarySnapshot[0].percentileValues; 59 | } else { 60 | return (); 61 | } 62 | } 63 | 64 | function testValueSummary() returns (float) { 65 | map tags = { "method": "DELETE" }; 66 | observe:Gauge gauge = new("response_size", "Size of a response.", tags); 67 | gauge.increment(); 68 | gauge.increment(1000.0); 69 | gauge.decrement(); 70 | gauge.decrement(500.0); 71 | return gauge.getValue(); 72 | } 73 | 74 | function testSummaryWithoutTags() returns (float) { 75 | observe:Gauge gauge = new("new_response_size"); 76 | gauge.setValue(1.0); 77 | gauge.setValue(2.0); 78 | gauge.setValue(3.0); 79 | observe:Snapshot[]? summarySnapshot = gauge.getSnapshot(); 80 | if summarySnapshot is observe:Snapshot[] { 81 | return summarySnapshot[0].mean; 82 | } else { 83 | return 0.0; 84 | } 85 | } 86 | 87 | function registerAndIncrement() returns (float) { 88 | observe:Gauge gauge = new("register_response_size"); 89 | checkpanic gauge.register(); 90 | gauge.increment(1); 91 | return gauge.getValue(); 92 | } 93 | -------------------------------------------------------------------------------- /ballerina-tests/src/test/java/io/ballerina/stdlib/observe/RegistryTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | package io.ballerina.stdlib.observe; 19 | 20 | import org.ballerinalang.test.BCompileUtil; 21 | import org.ballerinalang.test.BRunUtil; 22 | import org.ballerinalang.test.CompileResult; 23 | import org.testng.Assert; 24 | import org.testng.annotations.BeforeClass; 25 | import org.testng.annotations.Test; 26 | 27 | import java.nio.file.Path; 28 | import java.nio.file.Paths; 29 | 30 | /** 31 | * Test to verify the operations for global metrics registry. 32 | * 33 | * @since 0.980.0 34 | */ 35 | public class RegistryTest extends MetricTest { 36 | private CompileResult compileResult; 37 | 38 | @BeforeClass 39 | public void setup() { 40 | String resourceRoot = Paths.get("src", "test", "resources").toAbsolutePath().toString(); 41 | Path testResourceRoot = Paths.get(resourceRoot, "test-src"); 42 | compileResult = BCompileUtil. 43 | compile(testResourceRoot.resolve("metrics_registry_test.bal").toString()); 44 | } 45 | 46 | @Test(groups = "RegistryTest.testGetAllMetrics", dependsOnGroups = "SummaryTest.testRegisteredGauge") 47 | public void testGetAllMetrics() { 48 | Object returns = BRunUtil.invoke(compileResult, "getAllMetricsSize"); 49 | Assert.assertEquals(returns, 1L, 50 | "There shouldn't be any metrics registered in initial state."); 51 | } 52 | 53 | @Test(groups = "RegistryTest.testRegister", dependsOnMethods = "testGetAllMetrics") 54 | public void testRegister() { 55 | Object returns = BRunUtil.invoke(compileResult, "registerAngGetMetrics"); 56 | Assert.assertEquals(returns, 2L, 57 | "One metric should have been registered."); 58 | } 59 | 60 | @Test(dependsOnMethods = "testRegister") 61 | public void lookupMetric() { 62 | Object returns = BRunUtil.invoke(compileResult, "lookupRegisteredMetrics"); 63 | Assert.assertTrue((Boolean) returns, "Cannot be looked up a registered metric"); 64 | } 65 | 66 | @Test(dependsOnMethods = "lookupMetric") 67 | public void lookupWithOnlyNameMetric() { 68 | Object returns = BRunUtil.invoke(compileResult, "lookupRegisteredNameOnlyMetrics"); 69 | Assert.assertFalse((Boolean) returns, "No metric should be returned for only name without tags"); 70 | } 71 | 72 | @Test(dependsOnMethods = "lookupWithOnlyNameMetric") 73 | public void lookupMetricAndIncrement() { 74 | Object returns = BRunUtil.invoke(compileResult, "lookupRegisterAndIncrement"); 75 | Assert.assertTrue((Boolean) returns, "No metric should be returned for only name without tags"); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/mockextension/MetricsUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | package io.ballerina.stdlib.observe.mockextension; 20 | 21 | import com.google.gson.Gson; 22 | import com.google.gson.GsonBuilder; 23 | import io.ballerina.runtime.api.utils.JsonUtils; 24 | import io.ballerina.runtime.observability.metrics.Counter; 25 | import io.ballerina.runtime.observability.metrics.DefaultMetricRegistry; 26 | import io.ballerina.runtime.observability.metrics.Gauge; 27 | import io.ballerina.runtime.observability.metrics.Metric; 28 | import io.ballerina.runtime.observability.metrics.PolledGauge; 29 | import io.ballerina.stdlib.observe.mockextension.model.Metrics; 30 | import io.ballerina.stdlib.observe.mockextension.model.MockCounter; 31 | import io.ballerina.stdlib.observe.mockextension.model.MockGauge; 32 | import io.ballerina.stdlib.observe.mockextension.model.MockPolledGauge; 33 | import io.ballerina.stdlib.observe.mockextension.typeadapter.DurationTypeAdapter; 34 | 35 | import java.time.Duration; 36 | 37 | /** 38 | * Java functions called from Ballerina related to metrics. 39 | */ 40 | public class MetricsUtils { 41 | 42 | private static final Gson gson = new GsonBuilder() 43 | .registerTypeAdapter(Duration.class, new DurationTypeAdapter()) 44 | .create(); 45 | 46 | public static Object getMetrics() { 47 | Metric[] metricsList = DefaultMetricRegistry.getInstance().getAllMetrics(); 48 | Metrics metrics = new Metrics(); 49 | for (Metric metric : metricsList) { 50 | if (metric instanceof Counter counter) { 51 | MockCounter mockCounter = new MockCounter(); 52 | mockCounter.setId(counter.getId()); 53 | mockCounter.setValue(counter.getValue()); 54 | metrics.addCounter(mockCounter); 55 | } else if (metric instanceof Gauge gauge) { 56 | MockGauge mockGauge = new MockGauge(); 57 | mockGauge.setId(gauge.getId()); 58 | mockGauge.setValue(gauge.getValue()); 59 | mockGauge.setCount(gauge.getCount()); 60 | mockGauge.setSum(gauge.getSum()); 61 | mockGauge.setSnapshots(gauge.getSnapshots()); 62 | metrics.addGauge(mockGauge); 63 | } else if (metric instanceof PolledGauge polledGauge) { 64 | MockPolledGauge mockPolledGauge = new MockPolledGauge(); 65 | mockPolledGauge.setId(polledGauge.getId()); 66 | mockPolledGauge.setValue(polledGauge.getValue()); 67 | metrics.addPolledGauge(mockPolledGauge); 68 | } 69 | } 70 | return JsonUtils.parse(gson.toJson(metrics)); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /.github/workflows/central-publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish to the Ballerina central 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | environment: 7 | type: choice 8 | description: Select environment 9 | required: true 10 | options: 11 | - CENTRAL 12 | - DEV CENTRAL 13 | - STAGE CENTRAL 14 | 15 | jobs: 16 | publish-release: 17 | runs-on: ubuntu-latest 18 | if: github.repository_owner == 'ballerina-platform' 19 | steps: 20 | - uses: actions/checkout@v3 21 | - name: Set up JDK 21 22 | uses: actions/setup-java@v3 23 | with: 24 | distribution: 'temurin' 25 | java-version: 21 26 | - name: Build with Gradle 27 | env: 28 | packageUser: ${{ github.actor }} 29 | packagePAT: ${{ secrets.GITHUB_TOKEN }} 30 | run: ./gradlew build -x check -x test 31 | - name: Create lib directory if not exists 32 | run: mkdir -p ballerina/lib 33 | - name: Run Trivy vulnerability scanner 34 | uses: aquasecurity/trivy-action@master 35 | with: 36 | scan-type: 'rootfs' 37 | scan-ref: "${{ github.workspace }}/ballerina/lib" 38 | format: 'table' 39 | timeout: '10m0s' 40 | exit-code: '1' 41 | 42 | - name: Ballerina Central Push 43 | if: ${{ github.event.inputs.environment == 'CENTRAL' }} 44 | env: 45 | BALLERINA_DEV_CENTRAL: false 46 | BALLERINA_STAGE_CENTRAL: false 47 | BALLERINA_CENTRAL_ACCESS_TOKEN: ${{ secrets.BALLERINA_CENTRAL_ACCESS_TOKEN }} 48 | packageUser: ${{ secrets.BALLERINA_BOT_USERNAME }} 49 | packagePAT: ${{ secrets.BALLERINA_BOT_TOKEN }} 50 | GITHUB_TOKEN: ${{ secrets.BALLERINA_BOT_TOKEN }} 51 | CLIENT_ID: ${{ secrets.CLIENT_ID }} 52 | CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }} 53 | REFRESH_TOKEN: ${{ secrets.REFRESH_TOKEN }} 54 | run: | 55 | ./gradlew clean build -PpublishToCentral=true 56 | 57 | - name: Ballerina Central Dev Push 58 | if: ${{ github.event.inputs.environment == 'DEV CENTRAL' }} 59 | env: 60 | BALLERINA_DEV_CENTRAL: true 61 | BALLERINA_STAGE_CENTRAL: false 62 | BALLERINA_CENTRAL_ACCESS_TOKEN: ${{ secrets.BALLERINA_CENTRAL_DEV_ACCESS_TOKEN }} 63 | packageUser: ${{ secrets.BALLERINA_BOT_USERNAME }} 64 | packagePAT: ${{ secrets.BALLERINA_BOT_TOKEN }} 65 | GITHUB_TOKEN: ${{ secrets.BALLERINA_BOT_TOKEN }} 66 | CLIENT_ID: ${{ secrets.CLIENT_ID }} 67 | CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }} 68 | REFRESH_TOKEN: ${{ secrets.REFRESH_TOKEN }} 69 | run: | 70 | sed -i 's/version=\(.*\)-SNAPSHOT/version=\1/g' gradle.properties 71 | ./gradlew clean build -PpublishToCentral=true 72 | 73 | - name: Ballerina Central Stage Push 74 | if: ${{ github.event.inputs.environment == 'STAGE CENTRAL' }} 75 | env: 76 | BALLERINA_DEV_CENTRAL: false 77 | BALLERINA_STAGE_CENTRAL: true 78 | BALLERINA_CENTRAL_ACCESS_TOKEN: ${{ secrets.BALLERINA_CENTRAL_STAGE_ACCESS_TOKEN }} 79 | packageUser: ${{ secrets.BALLERINA_BOT_USERNAME }} 80 | packagePAT: ${{ secrets.BALLERINA_BOT_TOKEN }} 81 | GITHUB_TOKEN: ${{ secrets.BALLERINA_BOT_TOKEN }} 82 | CLIENT_ID: ${{ secrets.CLIENT_ID }} 83 | CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }} 84 | REFRESH_TOKEN: ${{ secrets.REFRESH_TOKEN }} 85 | run: | 86 | sed -i 's/version=\(.*\)-SNAPSHOT/version=\1/g' gradle.properties 87 | ./gradlew clean build -PpublishToCentral=true -------------------------------------------------------------------------------- /ballerina/modules/mockextension/metrics.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/jballerina.java; 18 | 19 | # Holds the key and value of tag. 20 | # + key - Key of the tag 21 | # + value - Value of the tag 22 | public type Tag record { 23 | string key; 24 | string value; 25 | }; 26 | 27 | # Holds parameters required to id a metric. 28 | # + name - Name of the metric 29 | # + description - Description for the metric 30 | # + tags - Tags included in metric 31 | public type MetricId record { 32 | string name; 33 | string description; 34 | Tag[] tags; 35 | }; 36 | 37 | # Holds percentile and value. 38 | # + percentile - Percentile 39 | # + value - Value 40 | public type PercentileValue record { 41 | float percentile; 42 | float value; 43 | }; 44 | 45 | # Holds a time duration. 46 | # + seconds - Time window in seconds 47 | # + nanos - Time window in nano seconds 48 | public type TimeWindow record { 49 | int seconds; 50 | int nanos; 51 | }; 52 | 53 | # Holds a snapshot of statistics. 54 | # + timeWindow - Time window 55 | # + min - Minimum value 56 | # + max - Maximum value 57 | # + mean - Mean value 58 | # + stdDev - Standard Deviation value 59 | # + percentileValues - Percentile values 60 | public type Snapshot record { 61 | TimeWindow timeWindow; 62 | float min; 63 | float max; 64 | float mean; 65 | float stdDev; 66 | PercentileValue[] percentileValues; 67 | }; 68 | 69 | # Holds counter related metrics data. 70 | # + id - Id value for counter 71 | # + value - Value 72 | public type Counter record { 73 | MetricId id; 74 | int value; 75 | }; 76 | 77 | # Holds gauge related metrics data. 78 | # + id - Id value for counter 79 | # + value - Value 80 | # + count - Number of occurrences 81 | # + sum - Summation 82 | # + snapshots - Snapshot values 83 | public type Gauge record { 84 | MetricId id; 85 | float value; 86 | int count; 87 | float sum; 88 | Snapshot[] snapshots; 89 | }; 90 | 91 | # Holds polled gauge related metrics data. 92 | # + id - Id value for PolledGauge 93 | # + value - Value 94 | public type PolledGauge record { 95 | MetricId id; 96 | float value; 97 | }; 98 | 99 | # Holds metrics data. 100 | # + counters - Counters associated with 101 | # + gauges - Gauges associated with 102 | # + polledGauges - PolledGauges associated with 103 | public type Metrics record { 104 | Counter[] counters; 105 | Gauge[] gauges; 106 | PolledGauge[] polledGauges; 107 | }; 108 | 109 | # Get all the current metrics. 110 | # 111 | # + return - Current metrics 112 | public isolated function getMetrics() returns Metrics { 113 | json metricsJson = externGetMetrics(); 114 | Metrics | error metrics = metricsJson.cloneWithType(Metrics); 115 | if (metrics is error) { 116 | panic error("cannot convert to Metrics record; json string: " + metricsJson.toJsonString(), metrics); 117 | } else { 118 | return metrics; 119 | } 120 | } 121 | 122 | # Get all the current metrics. 123 | # 124 | # + return - The metrics currently in the metrics registry as a json 125 | isolated function externGetMetrics() returns json = @java:Method { 126 | name: "getMetrics", 127 | 'class: "io.ballerina.stdlib.observe.mockextension.MetricsUtils" 128 | } external; 129 | -------------------------------------------------------------------------------- /native/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | plugins { 18 | id 'java-library' 19 | id 'checkstyle' 20 | id 'com.github.spotbugs' 21 | id 'jacoco' 22 | } 23 | 24 | description = 'Ballerina - Observability Natives' 25 | 26 | dependencies { 27 | checkstyle project(':checkstyle') 28 | checkstyle "com.puppycrawl.tools:checkstyle:${checkstylePluginVersion}" 29 | 30 | implementation group: 'org.ballerinalang', name: 'ballerina-lang', version: "${ballerinaLangVersion}" 31 | implementation group: 'org.ballerinalang', name: 'ballerina-runtime', version: "${ballerinaLangVersion}" 32 | implementation group: 'org.ballerinalang', name: 'metrics-extensions', version: "${ballerinaLangVersion}" 33 | 34 | implementation group: 'io.opentelemetry', name: 'opentelemetry-api', version: "${openTelemetryVersion}" 35 | implementation group: 'io.opentelemetry', name: 'opentelemetry-sdk-trace', version: "${openTelemetryVersion}" 36 | implementation group: 'io.opentelemetry', name: 'opentelemetry-sdk-testing', version: "${openTelemetryVersion}" 37 | implementation group: 'com.google.code.gson', name: 'gson', version: "${gsonVersion}" 38 | implementation group: 'org.slf4j', name: 'slf4j-jdk14', version: "${slf4jVersion}" 39 | } 40 | 41 | checkstyle { 42 | toolVersion '10.12.1' 43 | configFile rootProject.file("build-config/checkstyle/build/checkstyle.xml") 44 | configProperties = ["suppressionFile" : file("${rootDir}/build-config/checkstyle/build/suppressions.xml")] 45 | } 46 | 47 | def excludePattern = '**/module-info.java' 48 | tasks.withType(Checkstyle) { 49 | exclude excludePattern 50 | } 51 | 52 | checkstyleMain.dependsOn(":checkstyle:downloadCheckstyleRuleFiles") 53 | 54 | spotbugsMain { 55 | def classLoader = plugins["com.github.spotbugs"].class.classLoader 56 | def SpotBugsConfidence = classLoader.findLoadedClass("com.github.spotbugs.snom.Confidence") 57 | def SpotBugsEffort = classLoader.findLoadedClass("com.github.spotbugs.snom.Effort") 58 | effort = SpotBugsEffort.MAX 59 | reportLevel = SpotBugsConfidence.LOW 60 | reportsDir = file("$project.buildDir/reports/spotbugs") 61 | reports { 62 | html.enabled true 63 | text.enabled = true 64 | } 65 | def excludeFile = file('spotbugs-exclude.xml') 66 | if(excludeFile.exists()) { 67 | excludeFilter = excludeFile 68 | } 69 | } 70 | 71 | spotbugsTest { 72 | enabled = true 73 | } 74 | 75 | publishing { 76 | publications { 77 | mavenJava(MavenPublication) { 78 | groupId project.group 79 | artifactId "observe-native" 80 | version = project.version 81 | artifact jar 82 | } 83 | } 84 | 85 | repositories { 86 | maven { 87 | name = "GitHubPackages" 88 | url = uri("https://maven.pkg.github.com/ballerina-platform/module-ballerina-observe") 89 | credentials { 90 | username = System.getenv("publishUser") 91 | password = System.getenv("publishPAT") 92 | } 93 | } 94 | } 95 | } 96 | 97 | compileJava { 98 | doFirst { 99 | options.compilerArgs = [ 100 | '--module-path', classpath.asPath, 101 | ] 102 | classpath = files() 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | Ballerina Observe Internal Library 3 | =================== 4 | 5 | [![Build](https://github.com/ballerina-platform/module-ballerina-http/actions/workflows/build-timestamped-master.yml/badge.svg)](https://github.com/ballerina-platform/module-ballerinai-observe/actions/workflows/build-timestamped-master.yml) 6 | [![Trivy](https://github.com/ballerina-platform/module-ballerina-http/actions/workflows/trivy-scan.yml/badge.svg)](https://github.com/ballerina-platform/module-ballerinai-observe/actions/workflows/trivy-scan.yml) 7 | [![GitHub Last Commit](https://img.shields.io/github/last-commit/ballerina-platform/module-ballerina-http.svg)](https://github.com/ballerina-platform/module-ballerinai-observe/commits/master) 8 | [![codecov](https://codecov.io/gh/ballerina-platform/module-ballerina-observe/branch/master/graph/badge.svg)](https://codecov.io/gh/ballerina-platform/module-ballerina-observe) 9 | 10 | This module contains internal configurations and initializations for Ballerina observability. Ballerina supports observability out of the box. You can use the [module-ballerina-observe](https://github.com/ballerina-platform/module-ballerina-observe) in your Ballerina project and enable observability features. 11 | 12 | By default, observability is not included in the executable created by Ballerina. It can be added by using the `--observability-included` build flag or by adding the following section to the `Ballerina.toml` file. 13 | 14 | ## Build from the source 15 | 16 | ### Set Up the prerequisites 17 | 18 | 1. Download and install Java SE Development Kit (JDK) version 21 (from one of the following locations). 19 | 20 | * [Oracle](https://www.oracle.com/java/technologies/downloads/) 21 | 22 | * [OpenJDK](https://adoptopenjdk.net/) 23 | 24 | > **Note:** Set the JAVA_HOME environment variable to the path name of the directory into which you installed JDK. 25 | 26 | 2. Export your GitHub Personal access token with read package permissions as follows. 27 | 28 | export packageUser= 29 | export packagePAT= 30 | 31 | ### Build the source 32 | 33 | Execute the commands below to build from source. 34 | 35 | 1. To build the library: 36 | ``` 37 | ./gradlew clean build 38 | ``` 39 | 40 | 2. To run the integration tests: 41 | ``` 42 | ./gradlew clean test 43 | ``` 44 | 45 | 3. To run a group of tests 46 | ``` 47 | ./gradlew clean test -Pgroups= 48 | ``` 49 | 50 | 4. To build the package without the tests: 51 | ``` 52 | ./gradlew clean build -x test 53 | ``` 54 | 55 | 5. To debug the tests: 56 | ``` 57 | ./gradlew clean test -Pdebug= 58 | ``` 59 | 60 | 6. To debug with Ballerina language: 61 | ``` 62 | ./gradlew clean build -PbalJavaDebug= 63 | ``` 64 | 65 | 7. Publish the generated artifacts to the local Ballerina central repository: 66 | ``` 67 | ./gradlew clean build -PpublishToLocalCentral=true 68 | ``` 69 | 70 | 8. Publish the generated artifacts to the Ballerina central repository: 71 | ``` 72 | ./gradlew clean build -PpublishToCentral=true 73 | ``` 74 | 75 | ## Contribute to Ballerina 76 | 77 | As an open source project, Ballerina welcomes contributions from the community. 78 | 79 | For more information, go to the [contribution guidelines](https://github.com/ballerina-platform/ballerina-lang/blob/master/CONTRIBUTING.md). 80 | 81 | ## Code of conduct 82 | 83 | All contributors are encouraged to read the [Ballerina Code of Conduct](https://ballerina.io/code-of-conduct). 84 | 85 | ## Useful links 86 | 87 | * For more information go to the [`Observe` library](https://lib.ballerina.io/ballerina/observe/latest). 88 | * For example demonstrations of the usage, go to [Ballerina By Examples](https://ballerina.io/learn/by-example/). 89 | * Chat live with us via our [Discord server](https://discord.gg/ballerinalang). 90 | * Post all technical questions on Stack Overflow with the [#ballerina](https://stackoverflow.com/questions/tagged/ballerina) tag. 91 | * View the [Ballerina performance test results](https://github.com/ballerina-platform/ballerina-lang/blob/master/performance/benchmarks/summary.md). 92 | -------------------------------------------------------------------------------- /ballerina/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | import org.apache.tools.ant.taskdefs.condition.Os 19 | 20 | plugins { 21 | id 'io.ballerina.plugin' 22 | } 23 | 24 | description = 'Ballerina - Observability' 25 | 26 | def packageName = "observe" 27 | def packageOrg = "ballerina" 28 | 29 | def tomlVersion = stripBallerinaExtensionVersion("${project.version}") 30 | def ballerinaTomlFilePlaceHolder = new File("${project.rootDir}/build-config/resources/Ballerina.toml") 31 | def ballerinaTomlFile = new File("$project.projectDir/Ballerina.toml") 32 | 33 | def stripBallerinaExtensionVersion(String extVersion) { 34 | if (extVersion.matches(project.ext.timestampedVersionRegex)) { 35 | def splitVersion = extVersion.split('-'); 36 | if (splitVersion.length > 3) { 37 | def strippedValues = splitVersion[0..-4] 38 | return strippedValues.join('-') 39 | } else { 40 | return extVersion 41 | } 42 | } else { 43 | return extVersion.replace("${project.ext.snapshotVersion}", "") 44 | } 45 | } 46 | 47 | ballerina { 48 | packageOrganization = packageOrg 49 | module = packageName 50 | langVersion = ballerinaLangVersion 51 | } 52 | 53 | configurations { 54 | externalJars { 55 | transitive false 56 | } 57 | } 58 | 59 | dependencies { 60 | externalJars(group: 'org.testng', name: 'testng', version: "${testngVersion}") 61 | } 62 | 63 | task updateTomlFiles { 64 | doLast { 65 | def stdlibDependentTestngVersion = project.testngVersion 66 | def openTelemetryVersion = project.openTelemetryVersion 67 | def newBallerinaToml = ballerinaTomlFilePlaceHolder.text.replace("@project.version@", project.version) 68 | newBallerinaToml = newBallerinaToml.replace("@toml.version@", tomlVersion) 69 | newBallerinaToml = newBallerinaToml.replace("@testng.version@", stdlibDependentTestngVersion) 70 | newBallerinaToml = newBallerinaToml.replace("@opentelemetry.version@", openTelemetryVersion) 71 | ballerinaTomlFile.text = newBallerinaToml 72 | } 73 | } 74 | 75 | task commitTomlFiles { 76 | doLast { 77 | project.exec { 78 | ignoreExitValue true 79 | if (Os.isFamily(Os.FAMILY_WINDOWS)) { 80 | commandLine 'cmd', '/c', "git commit Ballerina.toml Dependencies.toml -m \"[Automated] Update the native jar versions\"" 81 | } else { 82 | commandLine 'sh', '-c', "git commit Ballerina.toml Dependencies.toml -m '[Automated] Update the native jar versions'" 83 | } 84 | } 85 | } 86 | } 87 | 88 | publishing { 89 | publications { 90 | maven(MavenPublication) { 91 | artifact source: createArtifactZip, extension: 'zip' 92 | } 93 | } 94 | 95 | repositories { 96 | maven { 97 | name = "GitHubPackages" 98 | url = uri("https://maven.pkg.github.com/ballerina-platform/module-${packageOrg}-${packageName}") 99 | credentials { 100 | username = System.getenv("publishUser") 101 | password = System.getenv("publishPAT") 102 | } 103 | } 104 | } 105 | } 106 | 107 | updateTomlFiles.dependsOn copyStdlibs 108 | 109 | build.dependsOn(":observe-native:build") 110 | test.dependsOn(":observe-native:build") 111 | build.dependsOn(":observe-ballerina:generatePomFileForMavenPublication") 112 | build.finalizedBy(":observe-ballerina-tests:build") 113 | test.finalizedBy(":observe-ballerina-tests:build") 114 | 115 | publishToMavenLocal.dependsOn build 116 | publish.dependsOn build 117 | -------------------------------------------------------------------------------- /ballerina-tests/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | apply plugin: 'java' 19 | 20 | dependencies { 21 | testImplementation group: 'org.ballerinalang', name: 'ballerina-runtime', version: "${ballerinaLangVersion}" 22 | testImplementation group: 'org.ballerinalang', name: 'ballerina-test-utils', version: "${ballerinaLangVersion}" 23 | testImplementation group: 'org.ballerinalang', name: 'ballerina-metrics-extension', version: "${ballerinaLangVersion}" 24 | testImplementation group: 'org.testng', name: 'testng', version: "${testngVersion}" 25 | } 26 | 27 | def ballerinaDist = "build/target/extracted-distributions" 28 | 29 | configurations { 30 | jbalTools { 31 | transitive false 32 | } 33 | testUtils { 34 | transitive false 35 | } 36 | } 37 | 38 | task unpackJballerinaTools(type: Copy) { 39 | configurations.jbalTools.resolvedConfiguration.resolvedArtifacts.each { artifact -> 40 | from zipTree(artifact.getFile()) 41 | into new File(ballerinaDist, "jballerina-tools-zip") 42 | } 43 | } 44 | 45 | task copyObserveStdlib { 46 | dependsOn(":observe-ballerina:build") 47 | dependsOn(unpackJballerinaTools) 48 | doLast { 49 | /* Copy Observe module */ 50 | copy { 51 | from "$project.rootDir/ballerina/build/bala_unzipped/bala" 52 | into "${ballerinaDist}/jballerina-tools-zip/jballerina-tools-${ballerinaLangVersion}/repo/bala" 53 | } 54 | } 55 | } 56 | 57 | def classFilesArray = [] 58 | 59 | task copyBallerinaClassFiles { 60 | doFirst { 61 | fileTree("$project.rootDir/ballerina/build/bal_build_target").include("**/*.jar").forEach { jar -> 62 | zipTree(jar).matching { 63 | exclude '**/tests/*' 64 | exclude '**/$_init.class' 65 | exclude '**/$value$Caller.class' 66 | exclude '**/$value$Detail.class' 67 | exclude '**/$value$DetailType.class' 68 | exclude '**/$value$EmptyIterator.class' 69 | exclude '**/$value$$anonType$_6.class' 70 | exclude '**/$value$$anonType$_*.class' 71 | exclude '**/$value$_Frame.class' 72 | include '**/*.class' 73 | }.each { file -> classFilesArray.push(file) } 74 | } 75 | } 76 | } 77 | 78 | jacocoTestReport { 79 | dependsOn test 80 | dependsOn copyBallerinaClassFiles 81 | additionalClassDirs files(classFilesArray) 82 | reports { 83 | xml.required = true 84 | html.required = true 85 | } 86 | } 87 | 88 | test { 89 | dependsOn(copyObserveStdlib) 90 | finalizedBy jacocoTestReport 91 | useTestNG() { 92 | suites 'src/test/resources/testng.xml' 93 | } 94 | systemProperty 'ballerina.home', "${ballerinaDist}/jballerina-tools-zip/jballerina-tools-${ballerinaLangVersion}" 95 | 96 | testLogging { 97 | events "PASSED", "FAILED", "SKIPPED" 98 | showStackTraces true 99 | showStandardStreams true 100 | events "failed" 101 | exceptionFormat "full" 102 | afterSuite { desc, result -> 103 | if (!desc.parent) { // will match the outermost suite 104 | def output = "Results: ${result.resultType} (${result.testCount} tests, ${result.successfulTestCount} successes, ${result.failedTestCount} failures, ${result.skippedTestCount} skipped)" 105 | def startItem = '| ', endItem = ' |' 106 | def repeatLength = startItem.length() + output.length() + endItem.length() 107 | println('\n' + ('-' * repeatLength) + '\n' + startItem + output + endItem + '\n' + ('-' * repeatLength)) 108 | } 109 | } 110 | } 111 | } 112 | 113 | -------------------------------------------------------------------------------- /ballerina/commons.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/jballerina.java; 18 | 19 | // Configurations 20 | configurable boolean enabled = false; 21 | configurable string provider = ""; 22 | configurable boolean metricsEnabled = false; 23 | configurable string metricsReporter = ""; 24 | configurable boolean tracingEnabled = false; 25 | configurable string tracingProvider = ""; 26 | configurable boolean metricsLogsEnabled = false; 27 | 28 | function init() returns error? { 29 | boolean isMissingMetricsReporter = ((enabled || metricsEnabled) && (provider == "" && metricsReporter == "")); 30 | boolean isMissingTracingProvider = ((enabled || tracingEnabled) && (provider == "" && tracingProvider == "")); 31 | if (isMissingMetricsReporter || isMissingTracingProvider) { 32 | string[] enabledObservers = []; 33 | string[] missingProviders = []; 34 | if (isMissingMetricsReporter) { 35 | enabledObservers.push("metrics"); 36 | missingProviders.push("metrics reporter"); 37 | } 38 | if (isMissingTracingProvider) { 39 | enabledObservers.push("tracing"); 40 | missingProviders.push("tracing provider"); 41 | } 42 | return error("Observability (" + " and ".join(...enabledObservers) + ") enabled without " + 43 | " and ".join(...missingProviders) + ". Please visit https://central.ballerina.io/ballerina/observe for " + 44 | "the list of officially supported Observability providers."); 45 | } 46 | 47 | externInitializeModule(); 48 | } 49 | 50 | # Check whether observability is enabled. 51 | # + return - observability enabled/disabled. 52 | public isolated function isObservabilityEnabled() returns boolean = @java:Method { 53 | name: "isObservabilityEnabled", 54 | 'class: "io.ballerina.runtime.observability.ObserveUtils" 55 | } external; 56 | 57 | # Check whether metrics is enabled. 58 | # + return - metrics enabled/disabled. 59 | public isolated function isMetricsEnabled() returns boolean = @java:Method { 60 | name: "isMetricsEnabled", 61 | 'class: "io.ballerina.runtime.observability.ObserveUtils" 62 | } external; 63 | 64 | # Check whether metrics logs is enabled. 65 | # + return - metrics enabled/disabled. 66 | public isolated function isMetricsLogsEnabled() returns boolean = @java:Method { 67 | name: "isMetricsLogsEnabled", 68 | 'class: "io.ballerina.runtime.observability.ObserveUtils" 69 | } external; 70 | 71 | # Retrieve metrics provider. 72 | # + return - metrics provider. 73 | public isolated function getMetricsProvider() returns string = @java:Method { 74 | name: "getMetricsProvider", 75 | 'class: "io.ballerina.runtime.observability.ObserveUtils" 76 | } external; 77 | 78 | # Retrieve metrics reporter. 79 | # + return - metrics reporter. 80 | public isolated function getMetricsReporter() returns string = @java:Method { 81 | name: "getMetricsReporter", 82 | 'class: "io.ballerina.runtime.observability.ObserveUtils" 83 | } external; 84 | 85 | # Check whether tracing is enabled. 86 | # + return - tracing enabled/disabled. 87 | public isolated function isTracingEnabled() returns boolean = @java:Method { 88 | name: "isTracingEnabled", 89 | 'class: "io.ballerina.runtime.observability.ObserveUtils" 90 | } external; 91 | 92 | # Retrieve tracer provider. 93 | # + return - Tracing provider. 94 | public isolated function getTracingProvider() returns string = @java:Method { 95 | name: "getTracingProvider", 96 | 'class: "io.ballerina.runtime.observability.ObserveUtils" 97 | } external; 98 | 99 | # Initializing the module. 100 | function externInitializeModule() = @java:Method { 101 | 'class: "io.ballerina.stdlib.observe.nativeimpl.Utils", 102 | name: "initializeModule" 103 | } external; 104 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/nativeimpl/GetAllMetrics.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * WSO2 Inc. licenses this file to you under the Apache License, 4 | * Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, 11 | * software distributed under the License is distributed on an 12 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | * KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations 15 | * under the License. 16 | * 17 | */ 18 | 19 | package io.ballerina.stdlib.observe.nativeimpl; 20 | 21 | import io.ballerina.runtime.api.Environment; 22 | import io.ballerina.runtime.api.creators.TypeCreator; 23 | import io.ballerina.runtime.api.creators.ValueCreator; 24 | import io.ballerina.runtime.api.types.PredefinedTypes; 25 | import io.ballerina.runtime.api.utils.StringUtils; 26 | import io.ballerina.runtime.api.values.BArray; 27 | import io.ballerina.runtime.api.values.BMap; 28 | import io.ballerina.runtime.api.values.BString; 29 | import io.ballerina.runtime.observability.metrics.Counter; 30 | import io.ballerina.runtime.observability.metrics.DefaultMetricRegistry; 31 | import io.ballerina.runtime.observability.metrics.Gauge; 32 | import io.ballerina.runtime.observability.metrics.Metric; 33 | import io.ballerina.runtime.observability.metrics.MetricConstants; 34 | import io.ballerina.runtime.observability.metrics.MetricId; 35 | import io.ballerina.runtime.observability.metrics.PolledGauge; 36 | import io.ballerina.runtime.observability.metrics.Tag; 37 | 38 | import java.util.Set; 39 | 40 | import static io.ballerina.stdlib.observe.nativeimpl.Utils.metricType; 41 | 42 | /** 43 | * This is the getAllMetrics function native implementation for the registered metrics. 44 | * This can be used by the metric reporters to report the metrics. 45 | * 46 | * @since 0.980.0 47 | */ 48 | 49 | public class GetAllMetrics { 50 | 51 | public static BArray getAllMetrics(Environment env) { 52 | Metric[] metrics = DefaultMetricRegistry.getInstance().getAllMetrics(); 53 | 54 | BArray bMetrics = ValueCreator.createArrayValue(TypeCreator.createArrayType(metricType)); 55 | int metricIndex = 0; 56 | for (Metric metric : metrics) { 57 | MetricId metricId = metric.getId(); 58 | Object metricValue = null; 59 | String metricType = null; 60 | BArray summary = null; 61 | if (metric instanceof Counter) { 62 | metricValue = ((Counter) metric).getValue(); 63 | metricType = MetricConstants.COUNTER; 64 | } else if (metric instanceof Gauge) { 65 | Gauge gauge = (Gauge) metric; 66 | metricValue = gauge.getValue(); 67 | metricType = MetricConstants.GAUGE; 68 | summary = Utils.createBSnapshots(env, gauge.getSnapshots()); 69 | } else if (metric instanceof PolledGauge) { 70 | PolledGauge gauge = (PolledGauge) metric; 71 | metricValue = gauge.getValue(); 72 | metricType = MetricConstants.GAUGE; 73 | } 74 | if (metricValue != null) { 75 | BMap metricStruct = ValueCreator.createRecordValue(env.getCurrentModule(), 76 | ObserveNativeImplConstants.METRIC); 77 | metricStruct.put(StringUtils.fromString("name"), StringUtils.fromString(metricId.getName())); 78 | metricStruct.put(StringUtils.fromString("desc"), StringUtils.fromString(metricId.getDescription())); 79 | metricStruct.put(StringUtils.fromString("tags"), getTags(metricId)); 80 | metricStruct.put(StringUtils.fromString("metricType"), StringUtils.fromString(metricType)); 81 | metricStruct.put(StringUtils.fromString("value"), metricValue); 82 | metricStruct.put(StringUtils.fromString("summary"), summary); 83 | bMetrics.add(metricIndex, metricStruct); 84 | metricIndex++; 85 | } 86 | } 87 | 88 | return bMetrics; 89 | } 90 | 91 | private static BMap getTags(MetricId metricId) { 92 | BMap bTags = ValueCreator.createMapValue(TypeCreator.createMapType( 93 | PredefinedTypes.TYPE_STRING)); 94 | Set tags = metricId.getTags(); 95 | for (Tag tag : tags) { 96 | bTags.put(StringUtils.fromString(tag.getKey()), StringUtils.fromString(tag.getValue())); 97 | } 98 | return bTags; 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/nativeimpl/LookupMetric.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * WSO2 Inc. licenses this file to you under the Apache License, 4 | * Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, 11 | * software distributed under the License is distributed on an 12 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | * KIND, either express or implied. See the License for the 14 | * specific language governing permissions and limitations 15 | * under the License. 16 | * 17 | */ 18 | 19 | package io.ballerina.stdlib.observe.nativeimpl; 20 | 21 | import io.ballerina.runtime.api.Environment; 22 | import io.ballerina.runtime.api.creators.TypeCreator; 23 | import io.ballerina.runtime.api.creators.ValueCreator; 24 | import io.ballerina.runtime.api.types.PredefinedTypes; 25 | import io.ballerina.runtime.api.utils.StringUtils; 26 | import io.ballerina.runtime.api.values.BArray; 27 | import io.ballerina.runtime.api.values.BMap; 28 | import io.ballerina.runtime.api.values.BObject; 29 | import io.ballerina.runtime.api.values.BString; 30 | import io.ballerina.runtime.observability.metrics.Counter; 31 | import io.ballerina.runtime.observability.metrics.DefaultMetricRegistry; 32 | import io.ballerina.runtime.observability.metrics.Gauge; 33 | import io.ballerina.runtime.observability.metrics.Metric; 34 | import io.ballerina.runtime.observability.metrics.MetricId; 35 | import io.ballerina.runtime.observability.metrics.PolledGauge; 36 | import io.ballerina.runtime.observability.metrics.Tag; 37 | import io.ballerina.runtime.observability.metrics.Tags; 38 | 39 | import java.util.HashSet; 40 | import java.util.Map; 41 | import java.util.Set; 42 | 43 | import static io.ballerina.stdlib.observe.nativeimpl.ObserveNativeImplConstants.COUNTER; 44 | import static io.ballerina.stdlib.observe.nativeimpl.ObserveNativeImplConstants.GAUGE; 45 | import static io.ballerina.stdlib.observe.nativeimpl.ObserveNativeImplConstants.METRIC_NATIVE_INSTANCE_KEY; 46 | 47 | /** 48 | * This is the lookupMetric function native implementation for the registered metrics. 49 | * 50 | * @since 0.980.0 51 | */ 52 | 53 | public class LookupMetric { 54 | 55 | public static Object lookupMetric(Environment env, BString metricName, Object tags) { 56 | 57 | Map tagMap = Utils.toStringMap((BMap) tags); 58 | Set tagSet = new HashSet<>(); 59 | Tags.tags(tagSet, tagMap); 60 | Metric metric = DefaultMetricRegistry.getInstance().lookup(new MetricId(metricName.getValue(), "", tagSet)); 61 | 62 | if (metric != null) { 63 | MetricId metricId = metric.getId(); 64 | if (metric instanceof Counter) { 65 | BObject counter = ValueCreator.createObjectValue( 66 | env.getCurrentModule(), COUNTER, StringUtils.fromString(metricId.getName()), 67 | StringUtils.fromString(metricId.getDescription()), getTags(metricId)); 68 | counter.addNativeData(METRIC_NATIVE_INSTANCE_KEY, metric); 69 | return counter; 70 | } else if (metric instanceof Gauge) { 71 | Gauge gauge = (Gauge) metric; 72 | BArray statisticConfigs = Utils.createBStatisticConfig(env, gauge.getStatisticsConfig()); 73 | BObject bGauge = ValueCreator.createObjectValue( 74 | env.getCurrentModule(), GAUGE, StringUtils.fromString(metricId.getName()), 75 | StringUtils.fromString(metricId.getDescription()), getTags(metricId), statisticConfigs); 76 | bGauge.addNativeData(METRIC_NATIVE_INSTANCE_KEY, metric); 77 | return bGauge; 78 | } else if (metric instanceof PolledGauge) { 79 | BArray statisticConfigs = Utils.createBStatisticConfig(env, null); 80 | BObject bGauge = ValueCreator.createObjectValue( 81 | env.getCurrentModule(), GAUGE, StringUtils.fromString(metricId.getName()), 82 | StringUtils.fromString(metricId.getDescription()), getTags(metricId), statisticConfigs); 83 | bGauge.addNativeData(METRIC_NATIVE_INSTANCE_KEY, metric); 84 | return bGauge; 85 | } 86 | } 87 | 88 | return null; 89 | } 90 | 91 | private static BMap getTags(MetricId metricId) { 92 | BMap bTags = ValueCreator.createMapValue(TypeCreator.createMapType( 93 | PredefinedTypes.TYPE_STRING)); 94 | Set tags = metricId.getTags(); 95 | for (Tag tag : tags) { 96 | bTags.put(StringUtils.fromString(tag.getKey()), StringUtils.fromString(tag.getValue())); 97 | } 98 | return bTags; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/mockextension/BMockSpan.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | * 18 | */ 19 | 20 | package io.ballerina.stdlib.observe.mockextension; 21 | 22 | import io.opentelemetry.api.common.Attributes; 23 | import io.opentelemetry.sdk.trace.data.EventData; 24 | 25 | import java.util.ArrayList; 26 | import java.util.HashMap; 27 | import java.util.List; 28 | import java.util.Map; 29 | import java.util.Objects; 30 | 31 | import static io.ballerina.runtime.observability.ObservabilityConstants.CHECKPOINT_EVENT_NAME; 32 | import static io.ballerina.runtime.observability.ObservabilityConstants.TAG_KEY_SRC_MODULE; 33 | import static io.ballerina.runtime.observability.ObservabilityConstants.TAG_KEY_SRC_POSITION; 34 | 35 | /** 36 | * Class that holds the mock spans of the tracing integration tests. 37 | */ 38 | public class BMockSpan { 39 | 40 | private String operationName; 41 | private String traceId; 42 | private String spanId; 43 | private String parentId; 44 | private Map tags; 45 | private List events; 46 | 47 | public BMockSpan(String operationName, String traceId, String spanId, String parentId, Map tags, 48 | List events) { 49 | this.operationName = operationName; 50 | this.traceId = traceId; 51 | this.spanId = spanId; 52 | this.parentId = parentId; 53 | this.tags = tags; 54 | this.events = events; 55 | } 56 | 57 | public BMockSpan(String operationName, String traceId, String spanId, String parentId, Attributes attributes, 58 | List eventDataList) { 59 | this.operationName = operationName; 60 | this.traceId = traceId; 61 | this.spanId = spanId; 62 | this.parentId = parentId; 63 | this.tags = new HashMap<>(); 64 | attributes.forEach((attributeKey, o) -> tags.put(attributeKey.getKey(), o)); 65 | this.events = new ArrayList<>(); 66 | for (EventData eventData : eventDataList) { 67 | HashMap tags = new HashMap<>(); 68 | eventData.getAttributes().forEach((attributeKey, o) -> tags.put(attributeKey.getKey(), o)); 69 | this.events.add(new BMockEvent(eventData.getName(), eventData.getEpochNanos(), tags)); 70 | } 71 | } 72 | 73 | public String getOperationName() { 74 | return operationName; 75 | } 76 | 77 | public void setOperationName(String operationName) { 78 | this.operationName = operationName; 79 | } 80 | 81 | public String getTraceId() { 82 | return traceId; 83 | } 84 | 85 | public void setTraceId(String traceId) { 86 | this.traceId = traceId; 87 | } 88 | 89 | public String getSpanId() { 90 | return spanId; 91 | } 92 | 93 | public void setSpanId(String spanId) { 94 | this.spanId = spanId; 95 | } 96 | 97 | public String getParentId() { 98 | return parentId; 99 | } 100 | 101 | public void setParentId(String parentId) { 102 | this.parentId = parentId; 103 | } 104 | 105 | public Map getTags() { 106 | return tags; 107 | } 108 | 109 | public void setTags(Map tags) { 110 | this.tags = tags; 111 | } 112 | 113 | public List getEvents() { 114 | return events; 115 | } 116 | 117 | public List getCheckpoints() { 118 | List checkpoints = null; 119 | if (getEvents() != null) { 120 | checkpoints = new ArrayList<>(getEvents().size()); 121 | for (BMockEvent mockEvent : getEvents()) { 122 | if (mockEvent.getName().equals(CHECKPOINT_EVENT_NAME)) { 123 | BMockSpan.CheckPoint checkpoint = new BMockSpan.CheckPoint( 124 | mockEvent.getTags().get(TAG_KEY_SRC_MODULE).toString(), 125 | mockEvent.getTags().get(TAG_KEY_SRC_POSITION).toString()); 126 | checkpoints.add(checkpoint); 127 | } 128 | } 129 | } 130 | return checkpoints; 131 | } 132 | 133 | /** 134 | * Control flow checkpoint. 135 | */ 136 | public static class CheckPoint { 137 | private final String moduleID; 138 | private final String positionID; 139 | 140 | public CheckPoint(String moduleID, String positionID) { 141 | this.moduleID = moduleID; 142 | this.positionID = positionID; 143 | } 144 | 145 | @Override 146 | public boolean equals(Object object) { 147 | if (this == object) { 148 | return true; 149 | } 150 | if (object == null || getClass() != object.getClass()) { 151 | return false; 152 | } 153 | CheckPoint that = (CheckPoint) object; 154 | return Objects.equals(moduleID, that.moduleID) && 155 | Objects.equals(positionID, that.positionID); 156 | } 157 | 158 | @Override 159 | public int hashCode() { 160 | return Objects.hash(moduleID, positionID); 161 | } 162 | } 163 | 164 | /** 165 | * This holds mock event. 166 | */ 167 | public static final class BMockEvent { 168 | private final String name; 169 | private final long timestampMicros; 170 | private final Map tags; 171 | 172 | public BMockEvent(String name, long timestampMicros, Map tags) { 173 | this.name = name; 174 | this.timestampMicros = timestampMicros; 175 | this.tags = tags; 176 | } 177 | 178 | public String getName() { 179 | return name; 180 | } 181 | 182 | public long getTimestampMicros() { 183 | return timestampMicros; 184 | } 185 | 186 | public Map getTags() { 187 | return tags; 188 | } 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/nativeimpl/Utils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | * 18 | */ 19 | 20 | package io.ballerina.stdlib.observe.nativeimpl; 21 | 22 | 23 | import io.ballerina.runtime.api.Environment; 24 | import io.ballerina.runtime.api.creators.TypeCreator; 25 | import io.ballerina.runtime.api.creators.ValueCreator; 26 | import io.ballerina.runtime.api.types.PredefinedTypes; 27 | import io.ballerina.runtime.api.types.Type; 28 | import io.ballerina.runtime.api.utils.StringUtils; 29 | import io.ballerina.runtime.api.values.BArray; 30 | import io.ballerina.runtime.api.values.BMap; 31 | import io.ballerina.runtime.api.values.BString; 32 | import io.ballerina.runtime.observability.metrics.PercentileValue; 33 | import io.ballerina.runtime.observability.metrics.Snapshot; 34 | import io.ballerina.runtime.observability.metrics.StatisticConfig; 35 | 36 | import java.util.HashMap; 37 | import java.util.Map; 38 | import java.util.Map.Entry; 39 | 40 | /** 41 | * This provides the util functions to observe related functions. 42 | */ 43 | public class Utils { 44 | 45 | static Type metricType; 46 | static Type statisticsConfigType; 47 | static Type percentileValueType; 48 | static Type snapshotType; 49 | 50 | public static void initializeModule(Environment env) { 51 | metricType = ValueCreator.createRecordValue(env.getCurrentModule(), 52 | ObserveNativeImplConstants.METRIC).getType(); 53 | statisticsConfigType = ValueCreator.createRecordValue(env.getCurrentModule(), 54 | ObserveNativeImplConstants.STATISTIC_CONFIG).getType(); 55 | percentileValueType = ValueCreator.createRecordValue(env.getCurrentModule(), 56 | ObserveNativeImplConstants.PERCENTILE_VALUE).getType(); 57 | snapshotType = ValueCreator.createRecordValue(env.getCurrentModule(), 58 | ObserveNativeImplConstants.SNAPSHOT).getType(); 59 | } 60 | 61 | public static Map toStringMap(BMap map) { 62 | Map returnMap = new HashMap<>(); 63 | if (map != null) { 64 | for (Entry keyVals : map.entrySet()) { 65 | Object value = keyVals.getValue(); 66 | returnMap.put(keyVals.getKey().toString(), value == null ? "()" : value.toString()); 67 | } 68 | } 69 | return returnMap; 70 | } 71 | 72 | public static BArray createBSnapshots(Environment env, Snapshot[] snapshots) { 73 | if (snapshots != null && snapshots.length > 0) { 74 | 75 | BArray bSnapshots = ValueCreator.createArrayValue(TypeCreator.createArrayType(snapshotType)); 76 | int index = 0; 77 | for (Snapshot snapshot : snapshots) { 78 | BArray bPercentiles = ValueCreator.createArrayValue(TypeCreator.createArrayType(percentileValueType)); 79 | int percentileIndex = 0; 80 | for (PercentileValue percentileValue : snapshot.getPercentileValues()) { 81 | BMap bPercentileValue = 82 | ValueCreator.createRecordValue(env.getCurrentModule(), 83 | ObserveNativeImplConstants.PERCENTILE_VALUE); 84 | bPercentileValue.put(StringUtils.fromString("percentile"), percentileValue.getPercentile()); 85 | bPercentileValue.put(StringUtils.fromString("value"), percentileValue.getValue()); 86 | bPercentiles.add(percentileIndex, bPercentileValue); 87 | percentileIndex++; 88 | } 89 | 90 | BMap aSnapshot = ValueCreator.createRecordValue( 91 | env.getCurrentModule(), ObserveNativeImplConstants.SNAPSHOT); 92 | aSnapshot.put(StringUtils.fromString("timeWindow"), snapshot.getTimeWindow().toMillis()); 93 | aSnapshot.put(StringUtils.fromString("mean"), snapshot.getMean()); 94 | aSnapshot.put(StringUtils.fromString("max"), snapshot.getMax()); 95 | aSnapshot.put(StringUtils.fromString("min"), snapshot.getMin()); 96 | aSnapshot.put(StringUtils.fromString("stdDev"), snapshot.getStdDev()); 97 | aSnapshot.put(StringUtils.fromString("percentileValues"), bPercentiles); 98 | bSnapshots.add(index, aSnapshot); 99 | index++; 100 | } 101 | return bSnapshots; 102 | } else { 103 | return null; 104 | } 105 | } 106 | 107 | public static BArray createBStatisticConfig(Environment env, StatisticConfig[] configs) { 108 | if (configs != null) { 109 | BArray bStatsConfig = ValueCreator.createArrayValue(TypeCreator.createArrayType(statisticsConfigType)); 110 | int index = 0; 111 | for (StatisticConfig config : configs) { 112 | BArray bPercentiles = ValueCreator.createArrayValue(TypeCreator.createArrayType( 113 | PredefinedTypes.TYPE_FLOAT)); 114 | int percentileIndex = 0; 115 | for (Double percentile : config.getPercentiles()) { 116 | bPercentiles.add(percentileIndex, percentile); 117 | percentileIndex++; 118 | } 119 | BMap aSnapshot = ValueCreator.createRecordValue(env.getCurrentModule(), 120 | ObserveNativeImplConstants.STATISTIC_CONFIG); 121 | aSnapshot.put(StringUtils.fromString("percentiles"), bPercentiles); 122 | aSnapshot.put(StringUtils.fromString("timeWindow"), config.getTimeWindow()); 123 | aSnapshot.put(StringUtils.fromString("buckets"), config.getBuckets()); 124 | bStatsConfig.add(index, aSnapshot); 125 | index++; 126 | } 127 | return bStatsConfig; 128 | } else { 129 | return ValueCreator.createArrayValue(TypeCreator.createArrayType(statisticsConfigType)); 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 87 | 88 | # Use the maximum available, or set MAX_FD != -1 to use that value. 89 | MAX_FD=maximum 90 | 91 | warn () { 92 | echo "$*" 93 | } >&2 94 | 95 | die () { 96 | echo 97 | echo "$*" 98 | echo 99 | exit 1 100 | } >&2 101 | 102 | # OS specific support (must be 'true' or 'false'). 103 | cygwin=false 104 | msys=false 105 | darwin=false 106 | nonstop=false 107 | case "$( uname )" in #( 108 | CYGWIN* ) cygwin=true ;; #( 109 | Darwin* ) darwin=true ;; #( 110 | MSYS* | MINGW* ) msys=true ;; #( 111 | NONSTOP* ) nonstop=true ;; 112 | esac 113 | 114 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 115 | 116 | 117 | # Determine the Java command to use to start the JVM. 118 | if [ -n "$JAVA_HOME" ] ; then 119 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 120 | # IBM's JDK on AIX uses strange locations for the executables 121 | JAVACMD=$JAVA_HOME/jre/sh/java 122 | else 123 | JAVACMD=$JAVA_HOME/bin/java 124 | fi 125 | if [ ! -x "$JAVACMD" ] ; then 126 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 127 | 128 | Please set the JAVA_HOME variable in your environment to match the 129 | location of your Java installation." 130 | fi 131 | else 132 | JAVACMD=java 133 | if ! command -v java >/dev/null 2>&1 134 | then 135 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 136 | 137 | Please set the JAVA_HOME variable in your environment to match the 138 | location of your Java installation." 139 | fi 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 147 | # shellcheck disable=SC3045 148 | MAX_FD=$( ulimit -H -n ) || 149 | warn "Could not query maximum file descriptor limit" 150 | esac 151 | case $MAX_FD in #( 152 | '' | soft) :;; #( 153 | *) 154 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 155 | # shellcheck disable=SC3045 156 | ulimit -n "$MAX_FD" || 157 | warn "Could not set maximum file descriptor limit to $MAX_FD" 158 | esac 159 | fi 160 | 161 | # Collect all arguments for the java command, stacking in reverse order: 162 | # * args from the command line 163 | # * the main class name 164 | # * -classpath 165 | # * -D...appname settings 166 | # * --module-path (only if needed) 167 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 168 | 169 | # For Cygwin or MSYS, switch paths to Windows format before running java 170 | if "$cygwin" || "$msys" ; then 171 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 172 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 173 | 174 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 175 | 176 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 177 | for arg do 178 | if 179 | case $arg in #( 180 | -*) false ;; # don't mess with options #( 181 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 182 | [ -e "$t" ] ;; #( 183 | *) false ;; 184 | esac 185 | then 186 | arg=$( cygpath --path --ignore --mixed "$arg" ) 187 | fi 188 | # Roll the args list around exactly as many times as the number of 189 | # args, so each arg winds up back in the position where it started, but 190 | # possibly modified. 191 | # 192 | # NB: a `for` loop captures its iteration list before it begins, so 193 | # changing the positional parameters here affects neither the number of 194 | # iterations, nor the values presented in `arg`. 195 | shift # remove old arg 196 | set -- "$@" "$arg" # push replacement arg 197 | done 198 | fi 199 | 200 | 201 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 202 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 203 | 204 | # Collect all arguments for the java command; 205 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 206 | # shell script including quotes and variable substitutions, so put them in 207 | # double quotes to make sure that they get re-expanded; and 208 | # * put everything else in single quotes, so that it's not re-expanded. 209 | 210 | set -- \ 211 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 212 | -classpath "$CLASSPATH" \ 213 | org.gradle.wrapper.GradleWrapperMain \ 214 | "$@" 215 | 216 | # Stop when "xargs" is not available. 217 | if ! command -v xargs >/dev/null 2>&1 218 | then 219 | die "xargs is not available" 220 | fi 221 | 222 | # Use "xargs" to parse quoted args. 223 | # 224 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 225 | # 226 | # In Bash we could simply go: 227 | # 228 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 229 | # set -- "${ARGS[@]}" "$@" 230 | # 231 | # but POSIX shell has neither arrays nor command substitution, so instead we 232 | # post-process each arg (as a line of input to sed) to backslash-escape any 233 | # character that might be a shell metacharacter, then use eval to reverse 234 | # that process (while maintaining the separation between arguments), and wrap 235 | # the whole thing up as a single "set" statement. 236 | # 237 | # This will of course break if any of these variables contains a newline or 238 | # an unmatched quote. 239 | # 240 | 241 | eval "set -- $( 242 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 243 | xargs -n1 | 244 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 245 | tr '\n' ' ' 246 | )" '"$@"' 247 | 248 | exec "$JAVACMD" "$@" 249 | -------------------------------------------------------------------------------- /native/src/main/java/io/ballerina/stdlib/observe/nativeimpl/OpenTracerBallerinaWrapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 Inc. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | * 18 | */ 19 | 20 | package io.ballerina.stdlib.observe.nativeimpl; 21 | 22 | import io.ballerina.runtime.api.Environment; 23 | import io.ballerina.runtime.api.creators.ErrorCreator; 24 | import io.ballerina.runtime.api.utils.StringUtils; 25 | import io.ballerina.runtime.api.values.BError; 26 | import io.ballerina.runtime.observability.ObserveUtils; 27 | import io.ballerina.runtime.observability.ObserverContext; 28 | import io.ballerina.runtime.observability.tracer.BSpan; 29 | import io.ballerina.runtime.observability.tracer.TracersStore; 30 | import io.ballerina.runtime.observability.tracer.TracingUtils; 31 | import io.opentelemetry.api.trace.Tracer; 32 | import org.slf4j.Logger; 33 | import org.slf4j.LoggerFactory; 34 | 35 | import java.util.HashMap; 36 | import java.util.Map; 37 | import java.util.concurrent.atomic.AtomicLong; 38 | 39 | import static io.ballerina.runtime.observability.ObservabilityConstants.DEFAULT_SERVICE_NAME; 40 | import static io.ballerina.runtime.observability.ObservabilityConstants.PROPERTY_ERROR_VALUE; 41 | import static io.ballerina.runtime.observability.ObservabilityConstants.TAG_KEY_ENTRYPOINT_FUNCTION_MODULE; 42 | import static io.ballerina.runtime.observability.ObservabilityConstants.TAG_KEY_ENTRYPOINT_FUNCTION_NAME; 43 | import static io.ballerina.runtime.observability.ObservabilityConstants.TAG_KEY_ENTRYPOINT_RESOURCE_ACCESSOR; 44 | import static io.ballerina.runtime.observability.ObservabilityConstants.TAG_KEY_ENTRYPOINT_SERVICE_NAME; 45 | 46 | /** 47 | * This class wraps opentracing apis and exposes extern functions to use within ballerina. 48 | */ 49 | public class OpenTracerBallerinaWrapper { 50 | 51 | private static final Logger log = LoggerFactory.getLogger(OpenTracerBallerinaWrapper.class); 52 | 53 | private static final OpenTracerBallerinaWrapper instance = new OpenTracerBallerinaWrapper(); 54 | private final TracersStore tracerStore; 55 | private final boolean enabled; 56 | private final Map observerContextMap = new HashMap<>(); 57 | private final AtomicLong spanIdCounter = new AtomicLong(); 58 | 59 | private static final int SYSTEM_TRACE_INDICATOR = -1; 60 | static final int ROOT_SPAN_INDICATOR = -2; 61 | 62 | private OpenTracerBallerinaWrapper() { 63 | 64 | enabled = ObserveUtils.isTracingEnabled(); 65 | tracerStore = TracersStore.getInstance(); 66 | } 67 | 68 | public static OpenTracerBallerinaWrapper getInstance() { 69 | 70 | return instance; 71 | } 72 | 73 | private long startSpan(ObserverContext observerContext, boolean isClient, String spanName) { 74 | 75 | observerContext.setOperationName(spanName); 76 | TracingUtils.startObservation(observerContext, isClient); 77 | long spanId = this.spanIdCounter.getAndIncrement(); 78 | observerContextMap.put(spanId, observerContext); 79 | return spanId; 80 | } 81 | 82 | /** 83 | * Method to start a span using parent span context. 84 | * 85 | * @param env native context 86 | * @param spanName name of the span 87 | * @param tags key value paired tags to attach to the span 88 | * @param parentSpanId id of parent span 89 | * @return unique id of the created span 90 | */ 91 | public long startSpan(Environment env, String spanName, Map tags, long parentSpanId) { 92 | 93 | if (!enabled) { 94 | return -1; 95 | } 96 | 97 | ObserverContext observerContext = new ObserverContext(); 98 | ObserverContext prevObserverContext = ObserveUtils.getObserverContextOfCurrentFrame(env); 99 | String serviceName; 100 | if (prevObserverContext != null) { 101 | serviceName = prevObserverContext.getServiceName(); 102 | String entrypointFunctionModule = prevObserverContext.getEntrypointFunctionModule(); 103 | String entrypointServiceName = prevObserverContext.getEntrypointServiceName(); 104 | String entrypointFunctionName = prevObserverContext.getEntrypointFunctionName(); 105 | String entrypointResourceAccessor = prevObserverContext.getEntrypointResourceAccessor(); 106 | observerContext.setEntrypointFunctionModule(entrypointFunctionModule); 107 | observerContext.setEntrypointServiceName(entrypointServiceName); 108 | observerContext.setEntrypointFunctionName(entrypointFunctionName); 109 | observerContext.setEntrypointResourceAccessor(entrypointResourceAccessor); 110 | observerContext.addTag(TAG_KEY_ENTRYPOINT_FUNCTION_MODULE, entrypointFunctionModule); 111 | observerContext.addTag(TAG_KEY_ENTRYPOINT_SERVICE_NAME, entrypointServiceName); 112 | observerContext.addTag(TAG_KEY_ENTRYPOINT_FUNCTION_NAME, entrypointFunctionName); 113 | observerContext.addTag(TAG_KEY_ENTRYPOINT_RESOURCE_ACCESSOR, entrypointResourceAccessor); 114 | } else { 115 | serviceName = DEFAULT_SERVICE_NAME; 116 | } 117 | observerContext.setServiceName(serviceName); 118 | 119 | Tracer tracer = tracerStore.getTracer(serviceName); 120 | if (tracer == null) { 121 | return -1; 122 | } 123 | tags.forEach((observerContext::addTag)); 124 | 125 | if (parentSpanId == SYSTEM_TRACE_INDICATOR) { 126 | observerContext.setSystemSpan(true); 127 | if (prevObserverContext != null) { 128 | observerContext.setParent(prevObserverContext); 129 | } 130 | ObserveUtils.setObserverContextToCurrentFrame(env, observerContext); 131 | return startSpan(observerContext, true, spanName); 132 | } else if (parentSpanId != ROOT_SPAN_INDICATOR) { 133 | ObserverContext parentOContext = observerContextMap.get(parentSpanId); 134 | if (parentOContext == null) { 135 | return -1; 136 | } 137 | observerContext.setParent(parentOContext); 138 | return startSpan(observerContext, true, spanName); 139 | } 140 | 141 | return startSpan(observerContext, true, spanName); 142 | } 143 | 144 | /** 145 | * Method to mark a span as finished. 146 | * 147 | * @param env current environment 148 | * @param spanId id of the Span 149 | * @return boolean to indicate if span was finished 150 | */ 151 | public boolean finishSpan(Environment env, long spanId) { 152 | 153 | if (!enabled) { 154 | return false; 155 | } 156 | ObserverContext observerContext = observerContextMap.get(spanId); 157 | if (observerContext != null) { 158 | if (observerContext.isSystemSpan()) { 159 | ObserveUtils.setObserverContextToCurrentFrame(env, observerContext.getParent()); 160 | } 161 | TracingUtils.stopObservation(observerContext); 162 | observerContext.setFinished(); 163 | observerContextMap.remove(spanId); 164 | return true; 165 | } else { 166 | return false; 167 | } 168 | } 169 | 170 | /** 171 | * Method to mark a span as finished. 172 | * 173 | * @param env current environment 174 | * @param spanId id of the Span 175 | * @return boolean to indicate if span was finished 176 | */ 177 | public boolean finishSpanWithError(Environment env, long spanId, BError error) { 178 | 179 | if (!enabled) { 180 | return false; 181 | } 182 | ObserverContext observerContext = observerContextMap.get(spanId); 183 | if (observerContext != null) { 184 | observerContext.addProperty(PROPERTY_ERROR_VALUE, error); 185 | if (observerContext.isSystemSpan()) { 186 | ObserveUtils.setObserverContextToCurrentFrame(env, observerContext.getParent()); 187 | } 188 | TracingUtils.stopObservation(observerContext); 189 | observerContext.setFinished(); 190 | observerContextMap.remove(spanId); 191 | return true; 192 | } else { 193 | return false; 194 | } 195 | } 196 | 197 | /** 198 | * Method to add tags to an existing span. 199 | * 200 | * @param env current environment 201 | * @param tagKey the key of the tag 202 | * @param tagValue the value of the tag 203 | * @param spanId id of the Span 204 | * @return Object to indicate if tag was added to the span 205 | */ 206 | public Object addTag(Environment env, String tagKey, String tagValue, long spanId) { 207 | 208 | if (!enabled) { 209 | return null; 210 | } 211 | 212 | final BSpan span; 213 | if (spanId == -1) { 214 | ObserverContext observer = ObserveUtils.getObserverContextOfCurrentFrame(env); 215 | if (observer == null) { 216 | // This is a case where the user has not started the tracing. 217 | // ObserverContext will be null if function is executed without entry point like main or resource 218 | // function ex. initialising phase. 219 | return null; 220 | } 221 | span = observer.getSpan(); 222 | } else { 223 | ObserverContext observerContext = observerContextMap.get(spanId); 224 | if (observerContext == null) { 225 | String errorMsg = 226 | "Could not find the trace for given span id. Can not add tag {" + tagKey + ":" + tagValue + 227 | "}"; 228 | log.info(errorMsg); 229 | return ErrorCreator.createError(StringUtils.fromString(errorMsg)); 230 | } 231 | span = observerContext.getSpan(); 232 | } 233 | 234 | span.addTag(tagKey, tagValue); 235 | return null; 236 | } 237 | } 238 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /ballerina/README.md: -------------------------------------------------------------------------------- 1 | ## Module Overview 2 | 3 | This module provides an API for observing Ballerina services. 4 | Ballerina supports Observability out of the box. This module provides an API to make observability more flexible for the Ballerina users. 5 | 6 | To observe the Ballerina code, the '--b7a.observability.enabled=true' property should be given when starting the service 7 | (i.e., `ballerina run hello_world.bal --b7a.observability.enabled=true'). 8 | 9 | ## Tracing 10 | Tracing provides information regarding the roundtrip of a service invocation based on the concept of spans, which are 11 | structured in a hierarchy based on the cause and effect concept. The tracing API allows users to tap into that 12 | tracing information, introduce new spans, and add additional information to existing spans using user-defined tags. 13 | 14 | ### Samples 15 | 16 | #### Start a root span & attach a child span 17 | 18 | The following code snippet shows an example of starting a root span with no parent and starting another span as a child of the first span. 19 | Note: Make sure that all started spans are closed properly to ensure that all spans are reported properly. 20 | 21 | ```ballerina 22 | int spanId = observe:startRootSpan("Parent Span"); 23 | 24 | // Do Something. 25 | 26 | int spanId2 = checkpanic observe:startSpan("Child Span", parentSpanId = spanId); 27 | 28 | // Do Something. 29 | 30 | var ret1 = observe:finishSpan(spanId2); 31 | 32 | // Do Something. 33 | 34 | var ret2 = observe:finishSpan(spanId); 35 | ``` 36 | 37 | #### Start a span attached to a system trace 38 | 39 | When no parentSpanId is given or a parentSpanId of -1 is given, a span is started as a child span to the current active span in the ootb system trace. 40 | 41 | ```ballerina 42 | int spanId = checkpanic observe:startSpan("Child Span"); 43 | 44 | // Do Something. 45 | 46 | var ret = observe:finishSpan(spanId); 47 | ``` 48 | 49 | #### Attach a tag to a span 50 | 51 | It is possible to add tags to the span by using the `observe:addTagToSpan()` function by providing the span id and relevant tag key and tag value. 52 | 53 | ```ballerina 54 | _ = observe:addTagToSpan(spanId = spanId, "Tag Key", "Tag Value"); 55 | ``` 56 | #### Attach a tag to a span in the system trace 57 | When no spanId is provided or -1 is given, the defined tags are added to the current active span in the ootb system trace. 58 | 59 | ```ballerina 60 | var ret = observe:addTagToSpan("Tag Key", "Tag Value"); 61 | ``` 62 | 63 | ## Metrics 64 | There are mainly two kind of metrics instances supported; Counter and Gauge. A counter is a cumulative metric that 65 | represents a single monotonically increasing counter whose value can only increase or be reset to zero on restart. 66 | For example, you can use a counter to represent the number of requests served, tasks completed, or errors. 67 | The Gauge metric instance represents a single numerical value that can arbitrarily go up and down, and also based on the 68 | statistics configurations provided to the Gauge, it can also report the statistics such as max, min, mean, percentiles, etc. 69 | 70 | ### Counter Samples 71 | 72 | #### Create 73 | The following code snippets provides the information on how Counter instances can be created. Instantiating the counter 74 | will simply create an instance based on the params passed. 75 | 76 | ```ballerina 77 | // Create counter with simply by name. 78 | observe:Counter simpleCounter = new("SimpleCounter"); 79 | 80 | // Create counter with description. 81 | observe:Counter counterWithDesc = new("CounterWithDesc", 82 | desc = "This is a sample counter description"); 83 | 84 | // Create counter with tags. 85 | map counterTags = { "method": "GET" }; 86 | observe:Counter counterWithTags = new("CounterWithTags", 87 | desc = "Some description", tags = counterTags); 88 | ``` 89 | 90 | #### Register 91 | The counter can be registered with the global metrics registry. Therefore, it can be looked up later without having the 92 | reference of the counter that was created. Also, only the registered counters will be reported to the Metrics reporter 93 | such as Prometheus. In case, if there is already another non counter metric registered, 94 | then there will be an error returned. But if it's another counter instance, then the registered counter instance will 95 | be returned. 96 | 97 | ```ballerina 98 | map counterTags = { "method": "GET" }; 99 | observe:Counter counterWithTags = new("CounterWithTags", 100 | desc = "Some description", tags = counterTags); 101 | var anyError = counterWithTags.register(); 102 | if anyError is error { 103 | log:printError("Cannot register the counter", err = anyError); 104 | } 105 | ``` 106 | 107 | #### Unregister 108 | The counter can be unregistered with the global metrics registry if it is already registered. If a metrics is unregistered, 109 | then further it'll not be included in metrics reporting. 110 | 111 | ```ballerina 112 | map counterTags = { "method": "GET" }; 113 | observe:Counter counterWithTags = new("CounterWithTags", 114 | desc = "Some description", tags = counterTags); 115 | var anyError = counterWithTags.register(); 116 | if anyError is error { 117 | log:printError("Cannot register the counter", err = anyError); 118 | } 119 | counterWithTags.unregister(); 120 | 121 | ``` 122 | 123 | #### Increment 124 | The counter can be incremented without passing any params (defaulted to 1), or by a specific amount. 125 | 126 | ```ballerina 127 | map counterTags = { "method": "GET" }; 128 | observe:Counter counterWithTags = new("CounterWithTags", 129 | desc = "Some description", tags = counterTags); 130 | // Increment by 1. 131 | counterWithTags.increment(); 132 | // Increment by amount 10. 133 | counterWithTags.increment(amount = 10); 134 | ``` 135 | 136 | #### Reset 137 | The counter can be resetted to default amount = 0. 138 | 139 | ```ballerina 140 | map counterTags = { "method": "GET" }; 141 | observe:Counter counterWithTags = new("CounterWithTags", 142 | desc = "Some description", tags = counterTags); 143 | counterWithTags.reset(); 144 | ``` 145 | 146 | #### Get Value 147 | The current value can be retrieved by this operation. 148 | 149 | ```ballerina 150 | map counterTags = { "method": "GET" }; 151 | observe:Counter counterWithTags = new("CounterWithTags", 152 | desc = "Some description", tags = counterTags); 153 | int currentValue = counterWithTags.getValue(); 154 | ``` 155 | 156 | ### Gauge Samples 157 | 158 | #### Create 159 | The following code snippets provides the information on how Gauge instances can be created. Instantiating the gauge 160 | will simply create an instance based on the params passed. 161 | 162 | ```ballerina 163 | // Create gauge with simply by name. 164 | // Uses the default statistics configuration. 165 | observe:Gauge simpleGauge = new("SimpleGauge"); 166 | 167 | // Create gauge with description. 168 | // Uses the default statistics configuration. 169 | observe:Gauge gaugeWithDesc = new("GaugeWithDesc", 170 | desc = "This is a sample gauge description"); 171 | 172 | // Create gauge with tags. 173 | // Uses the default statistics configuration. 174 | map gaugeTags = { "method": "GET" }; 175 | observe:Counter gaugeWithTags = new("GaugeWithTags", 176 | desc = "Some description", tags = gaugeTags); 177 | 178 | // Create gauge with disabled statistics. 179 | observe:StatisticConfig[] statsConfigs = []; 180 | observe:Gauge gaugeWithNoStats = new("GaugeWithTags", 181 | desc = "Some description", tags = gaugeTags, statisticConfig = statsConfigs); 182 | 183 | // Create gauge with statistics config. 184 | observe:StatisticConfig config = { timeWindow: 30000, 185 | percentiles: [0.33, 0.5, 0.9, 0.99], buckets: 3 }; 186 | statsConfigs[0]=config; 187 | 188 | observe:Gauge gaugeWithStats = new("GaugeWithTags", 189 | desc = "Some description", tags = gaugeTags, statisticConfig = statsConfigs); 190 | ``` 191 | 192 | #### Register 193 | The gauge can be registered with the global metrics registry, therefore it can be looked up later without having the 194 | reference of the gauge that was created. Also, only the registered counters will be reported to the Metrics reporter 195 | such as Prometheus. In case, if there is already another non gauge metric registered, 196 | then there will be an error returned. But if it's another gauge instance, then the registered gauge instance will 197 | be returned. 198 | 199 | ```ballerina 200 | map gaugeTags = { "method": "GET" }; 201 | observe:Gauge gaugeWithTags = new("GaugeWithTags", 202 | desc = "Some description", tags = gaugeTags); 203 | var anyError = gaugeWithTags.register(); 204 | if anyError is error { 205 | log:printError("Cannot register the gauge", err = anyError); 206 | } 207 | ``` 208 | 209 | #### Unregister 210 | The gauge can be unregistered with the global metrics registry if it is already registered. 211 | If a metrics is unregistered, then further it'll not be included in metrics reporting. 212 | 213 | ```ballerina 214 | map gaugeTags = { "method": "GET" }; 215 | observe:Gauge gaugeWithTags = new("GaugeWithTags", 216 | desc = "Some description", tags = gaugeTags); 217 | var anyError = gaugeWithTags.register(); 218 | if anyError is error { 219 | log:printError("Cannot register the gauge", err = anyError); 220 | } 221 | gaugeWithTags.unregister(); 222 | ``` 223 | 224 | #### Increment 225 | The gauge can be incremented without passing any params (defaulted to 1.0), or by a specific amount. 226 | 227 | ```ballerina 228 | map gaugeTags = { "method": "GET" }; 229 | observe:Gauge gaugeWithTags = new("GaugeWithTags", 230 | desc = "Some description", tags = gaugeTags); 231 | // Increment by 1. 232 | gaugeWithTags.increment(); 233 | // Increment by amount 10. 234 | gaugeWithTags.increment(amount = 10.0); 235 | ``` 236 | 237 | #### Decrement 238 | The gauge can be decremented without passing any params (defaulted to 1.0), or by a specific amount. 239 | 240 | ```ballerina 241 | map gaugeTags = { "method": "GET" }; 242 | observe:Gauge gaugeWithTags = new("GaugeWithTags", 243 | desc = "Some description", tags = gaugeTags); 244 | // Increment by 1. 245 | gaugeWithTags.decrement(); 246 | // Increment by amount 10. 247 | gaugeWithTags.decrement(amount = 10.0); 248 | ``` 249 | 250 | #### Set Value 251 | This method sets the gauge's value with specific amount. 252 | 253 | ```ballerina 254 | map gaugeTags = { "method": "GET" }; 255 | observe:Gauge gaugeWithTags = new("GaugeWithTags", 256 | desc = "Some description", tags = gaugeTags); 257 | gaugeWithTags.setValue(100.0); 258 | ``` 259 | 260 | #### Get Value 261 | The current value can be retrieved by this operation. 262 | 263 | ```ballerina 264 | map gaugeTags = { "method": "GET" }; 265 | observe:Gauge gaugeWithTags = new("GaugeWithTags", 266 | desc = "Some description", tags = gaugeTags); 267 | float currentValue = gaugeWithTags.getValue(); 268 | ``` 269 | 270 | #### Get Snapshot 271 | This method retrieves current snapshot of the statistics calculation based on the configurations passed to the gauge. 272 | If the statistics are disabled, then it'll be returning nil (). 273 | 274 | ```ballerina 275 | map gaugeTags = { "method": "GET" }; 276 | observe:Gauge gaugeWithTags = new("GaugeWithTags", 277 | desc = "Some description", tags = gaugeTags); 278 | gaugeWithTags.setValue(1.0); 279 | gaugeWithTags.setValue(2.0); 280 | gaugeWithTags.setValue(3.0); 281 | 282 | observe:Snapshot[]? summarySnapshot = gaugeWithTags.getSnapshot(); 283 | if summarySnapshot is observe:Snapshot[] { 284 | io:println(summarySnapshot); 285 | } else { 286 | io:println("No statistics available!"); 287 | } 288 | ``` 289 | 290 | ### Global Metrics Samples 291 | 292 | #### Get All Metrics 293 | This method returns all the metrics that are registered in the global metrics registry. This method is mainly useful for 294 | metric reporters, where they can fetch all metrics, format those, and report. 295 | 296 | ```ballerina 297 | observe:Metric[] metrics = observe:getAllMetrics(); 298 | foreach var metric in metrics { 299 | // Do something. 300 | } 301 | ``` 302 | 303 | #### Lookup Metric 304 | This method will lookup for the metric from the global metric registry and return it. 305 | 306 | ```ballerina 307 | map tags = { "method": "GET" }; 308 | observe:Counter|observe:Gauge|() metric = observe:lookupMetric("MetricName", 309 | tags = tags); 310 | if metric is observe:Counter { 311 | metric.increment(amount = 10); 312 | } else if metric is observe:Gauge { 313 | metric.increment(amount = 10.0); 314 | } else { 315 | io:println("No Metric Found!"); 316 | } 317 | ``` 318 | --------------------------------------------------------------------------------